QButtonGroup does not emit the 'ButtonToggled' signal when clicked



  • I am trying to display a simple group of two radio buttons, but for some reason the buttonToggled signal is not emitted when I click on the radio buttons.
    Here's a code sample of what I am trying to do:

    class MainForm(QDialog):
    
    	def __init__(self, parent = None):
    		super(MainForm, self).__init__(parent)
    
    		button_a = QRadioButton('Option A')
    		button_b = QRadioButton('Option B')
    		button_a.setChecked(True)
    
    		button_group = QButtonGroup()
    		button_group.addButton(button_a)
    		button_group.addButton(button_b)
    		button_group.buttonToggled.connect(self.on_button_signal)
    
    		group_box = QGroupBox('Options')
    		buttons_vbox = QVBoxLayout()
    		buttons_vbox.addWidget(button_a)
    		buttons_vbox.addWidget(button_b)
    		group_box.setLayout(buttons_vbox)
    
    		
    		hbox = QHBoxLayout()
    		hbox.addWidget(group_box)
    		self.setLayout(hbox)
    
    	@pyqtSlot(QAbstractButton, bool)
    	def on_button_signal(self, button, checked):
    		if checked:
    			print('do something with {0}'.format(button.text()))
    
    
    
    def run_app():
    	app = QApplication(sys.argv)
    	form = MainForm()
    	form.show()
    	app.exec_()
    
    if __name__ == '__main__':
    	run_app()
    

    The above code produces the following:
    0_1506159326742_2907e13a-1c6d-4e55-a828-99b13ebb1c0c-image.png

    But the 'on_button_signal()' function never invoked when switching between options.
    What am I doing wrong here?

    BTW, is there a way to emit signal only when the button is transitions from off to on?
    This could spare the rather unneeded 'if checked' condition + spare the unneeded emitted signal when button transitions from on to off.
    Thanks.



  • I am no expert, just starting out managing someone else's PyQt application.

    Looking through the code I have inherited, I see that it attaches each button's button.toggled.connect(...) instead of your button_group.buttonToggled.connect(...) It also does a buttonGroup.setExclusive(True). Do either of those help any?

    Plus no sign of any @pyqtSlot in code.

    Also I see the handlers all check state, no evidence of an "off-to-on-only" event.

    P.S.
    Docs for QButtonGroup state:

    If a button is clicked, the buttonClicked() signal is emitted; for a checkable button in an exclusive group this means that the button has been checked.

    and

    This [buttonClicked()] signal is emitted when the given button is clicked. A button is clicked when it is first pressed and then released, when its shortcut key is typed, or when QAbstractButton::click() or QAbstractButton::animateClick() is programmatically called.

    Apart from trying that signal instead of toggled, doesn't that imply signal only on button clicked to On, not to Off, just like you want?

    (BTW, I do assume you have verified the whole handler is not invoked, not just relying on the value of checked.)

    Finally --- and I may be way out of line on this --- your button_group = QButtonGroup() assigns just a local variable, which will have gone out of scope at end of __init__(). If you try self.button_group instead, does that make any difference?



  • Great!
    For main problem:
    Indeed, I didn't notice that QButtonGroup is the only object that has no live reference...
    So, when the initializer ends, the object goes out of scope, and dies...
    When I added it as a class member it did the trick.

    For the second:
    toggled also means that the handler will be called when button goes from 'off' to 'on' (I verified it), so, for example, when I click on 'option B' button, the handler is invoked twice: once for 'option A' button with checked = False, and second time for 'option B' button, with checked = True.
    It's not a big deal, since like you see I can ignore the off-to-on signal by inspecting the checked, I was just wondering if there's a more elegant way to do that.

    Thanks you so much!



  • When I added it as a class member it did the trick.

    I am happy that using self.button_group = ... has retained the reference for you as you need. In my code, all these widgets are stored into self.... so they always stay in scope as long as the dialog does.

    [toggled] I was just wondering if there's a more elegant way to do that

    I am indeed suggesting to you that there is a neater way to recognise switching a button On, but you don't seem to have tried my suggestion!

    But, first you wrote:

    BTW, is there a way to emit signal only when the button is transitions from off to on?

    and later you write:

    since like you see I can ignore the off-to-on signal by inspecting the checked

    Those contradict! Do you wish to recognise Off->On or On->Off ?? :)

    Assuming you want the most usual Off->On, replace button_group.buttonToggled.connect(...) by button_group.buttonClicked.connect(...). buttonClicked is fired only when a button is switched On (fired only once, and passes no checked parameter since that would always be True), whereas buttonToggled is called on both buttons for Off and On (and you have to examine checked). If you only want to know about Off->On, use buttonClicked.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.