Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pyqt - What signal does my standard "Apply" button emit and how do I write the slot for it?

I'm just learning pyqt and I'm trying to understand Standard buttons. I'm just learning, so let me know if I did something grossly wrong.

I've created a simple UI with some standard buttons in QT Designer.

I noted that the accepted() and rejected() signals are being connected to the accept and reject slots, so I wrote them. The Ok button and cancel button work as expected, but the Apply button simply doesn't react. How do I connect the apply button to a slot?

sample.py - Here's my sample app code:

import sys
from PyQt4 import QtGui

import designer

class SampleApp(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self,parent)
        self.ui = designer.Ui_Dialog()
        self.ui.setupUi(self)

    def reject(w):
        print("reject", w)
        w.close()

    def accept(w):
        print("accept", w)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    myapp = SampleApp()
    myapp.show()
    sys.exit(app.exec_())

designer.py - Here's the auto-generated QT Designer code:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'designer.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.resize(554, 399)
        self.buttonBox = QtGui.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(190, 340, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Apply|QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.Ok)
        self.buttonBox.setCenterButtons(False)
        self.buttonBox.setObjectName(_fromUtf8("buttonBox"))

        self.retranslateUi(Dialog)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), Dialog.accept)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))
like image 986
StackQuestions Avatar asked Feb 16 '16 21:02

StackQuestions


People also ask

What is signal and slot in PyQt5?

PyQt5 has a unique signal and slot mechanism to deal with events. Signals and slots are used for communication between objects. A signal is emitted when a particular event occurs. A slot can be any Python callable.

What is QThread in PyQt5?

In PyQt, you use QThread to create and manage worker threads. According to Qt's documentation, there are two main ways to create worker threads with QThread : Instantiate QThread directly and create a worker QObject , then call .

Is PyQt thread safe?

While some parts of the Qt framework are thread safe, much of it is not. The Qt C++ documentation provides a good overview of which classes are reentrant (can be used to instantiate objects in multiple threads).

How to display text in the details area of PySide2 qmessagebox?

PySide2.QtWidgets.QMessageBox.setDefaultButton(button) Sets the message box’s default button to button . This property holds the text to be displayed in the details area..

How to set the icon of the message box in PySide?

This property holds the message box’s icon. The icon of the message box can be specified with one of the values: The default is NoIcon . The pixmap used to display the actual icon depends on the current GUI style . You can also set a custom pixmap for the icon by setting the icon pixmap property. PySide2.QtWidgets.QMessageBox.setIconPixmap(pixmap)

What are the different types of signals emitted by a button?

For convenience, if the button has an AcceptRole , RejectRole , or HelpRole , the accepted () , rejected () , or helpRequested () signals are emitted respectively. If you want a specific button to be default you need to call setDefault () on it yourself.

How to implement the effect of the Apply button?

To implement the effect of the Apply button, the property sheet must tell its owner, or some other external object in the application, to apply the current settings in the property pages.


3 Answers

You don't need to write slots for accept() and reject(), because the QDialog class already has them.

When you create a new form and choose "Dialog with Buttons", it will add a button-box with Ok and Cancel buttons, and the accepted()/rejected() signals will be automatically connected to the dialog's existing accept() and reject() slots.

But note that there is no one-to-one relationship between the buttons and signals. Instead, there is a set of button roles, and each standard button is assigned one of those roles. All buttons with the AcceptRole will emit the accepted() signal, those with the RejectRole will emit the rejected() signal, whilst those with the HelpRole will emit the helpRequested() signal. But the other roles (such as the ApplyRole), do not emit any specific signals other than clicked().

To handle these other buttons you can either connect to each one directly:

button = self.ui.buttonBox.button(QDialogButtonBox.Apply)
button.clicked.connect(self.handleApply)

or handle them all in a single slot like this:

class SampleApp(QWidget):  
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = designer.Ui_Dialog()
        self.ui.setupUi(self)
        self.ui.buttonBox.clicked.connect(self.handleButtonClick)

    def handleButtonClick(self, button):
        role = self.buttonBox.buttonRole(button)
        if role == QDialogButtonBox.ApplyRole:
            print('Apply Clicked')
        elif role == QDialogButtonBox.ResetRole:
            print('Reset Clicked')        
        # and so on...
like image 121
ekhumoro Avatar answered Nov 14 '22 22:11

ekhumoro


You'll need to connect the clicked signal from the Apply button manually in your widget.

class SampleApp(QtGui.QWidget):

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self,parent)
        self.ui = designer.Ui_Dialog()
        self.ui.setupUi(self)
        btn = self.ui.buttonBox.button(QtGui.QDialogButtonBox.Apply)
        btn.clicked.connect(self.accept)
like image 28
Brendan Abel Avatar answered Nov 14 '22 22:11

Brendan Abel


You need to get the button from the QDialogButtonBox and connect clicked signal to the desired slot. Also I suggest you to use the new-style signal and slots support which is way more intuitive:

Here below you define the slots to be triggered. You should decorate them using the @pyqtSlot() decorator. It would work also without the decorator (more info in the documentation page).

import sys
import designer

from PyQt4 import QtGui, QtCore


class SampleApp(QtGui.QWidget):

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self,parent)
        self.ui = designer.Ui_Dialog()
        self.ui.setupUi(self)

    @QtCore.pyqtSlot()
    def reject(self):
        print("reject")
        self.close()

    @QtCore.pyqtSlot()
    def accept(self):
        print("accept")

    @QtCore.pyqtSlot()
    def apply(self):
        print("apply")


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    myapp = SampleApp()
    myapp.show()
    sys.exit(app.exec_())

Here below instead you connect the clicked action of the buttons to the slots you defined up here. Note that for Close and Ok that was not really necessary because when using StandardButtons PyQt automatically connect them to the default actions if not specified by the programmer. Although I connected them manually so you get the idea of what's going on.

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'designer.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_Dialog(object):

    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.resize(554, 399)
        self.buttonBox = QtGui.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(190, 340, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Apply|QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.Ok)
        self.buttonBox.setCenterButtons(False)
        self.buttonBox.setObjectName(_fromUtf8("buttonBox"))

        self.retranslateUi(Dialog)

        self.buttonBox.button(QtGui.QDialogButtonBox.Close).clicked.connect(Dialog.reject)
        self.buttonBox.button(QtGui.QDialogButtonBox.Ok).clicked.connect(Dialog.accept)
        self.buttonBox.button(QtGui.QDialogButtonBox.Apply).clicked.connect(Dialog.apply)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))
like image 44
Daniele Pantaleone Avatar answered Nov 14 '22 21:11

Daniele Pantaleone