Home > database >  Return clicked button id instead of (accept, reject flags) on QDialog- PyQt5
Return clicked button id instead of (accept, reject flags) on QDialog- PyQt5

Time:03-06

Summary:

I've been using QMessageBox in my application (for this purpose asking for saving project before closing, Error messages), And now I want to have a custom style (Custom title bar, custom buttons and so on), I found it is hard to do that with QMessageBox, And since I've been using a QDialog in my application as well (For this purpose: Taking input from user), I decided to use a custom QDialog (Make my own style on it) instead of QMessageBox for these all previous purpose, since it is easier to customize and creating my style.

The problem:

The problem that I have now is: QDialog return only a flag value (0,1) depending on the button role And that's fine if I have only 2 buttons BUT here I have 3 (Save, Cancel, Close), Save will return 1 and both Close and Cancel return 0. And QMessageBox as I've seen it return the id of the Button that was clicked.

An example (commented well hopefully :D):

from PyQt5.QtWidgets import *


class CustomDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Data will be lost")
        label = QLabel("Are you sure you want close the app before saving?")
        buttonBox = QDialogButtonBox()
        buttonBox.addButton(QDialogButtonBox.Save)
        buttonBox.addButton(QDialogButtonBox.Cancel)
        buttonBox.addButton(QDialogButtonBox.Close)

        layout = QVBoxLayout()
        layout.addWidget(label)
        layout.addWidget(buttonBox)
        self.resize(300, 100)
        self.setLayout(layout)

        # These two lines, return 0 or 1.
        buttonBox.rejected.connect(self.reject)
        buttonBox.accepted.connect(self.accept)    

class Window(QWidget):
    def __init__(self):
        super().__init__()
        label = QLabel('Hello Dialog', self)
        open_dialog_button = QPushButton('Open Dialog', self)
        open_dialog_button.clicked.connect(self.showDialog)

        open_message_box_button = QPushButton('Open Message Box', self)
        open_message_box_button.clicked.connect(self.show_message_box)

        layout = QVBoxLayout()
        layout.addWidget(label)
        layout.addWidget(open_dialog_button)
        layout.addWidget(open_message_box_button)
        self.setLayout(layout)

    def showDialog(self):
        self.dialog = CustomDialog(self)
        btn_clicked = self.dialog.exec_()  # dialog exec returns 0 or 1 (Save = 1, Close and Cancel returns 0)

        # I want something like this.
        if btn_clicked == QDialogButtonBox.Save:
            print("Close.. After Saving...")
        elif btn_clicked == QDialogButtonBox.Close:
            print("Close.. Without saving")
        else:
            print("Cancel.. Don't exit the program")

    def show_message_box(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText("Are you sure you want close the app before saving?")
        msg.setStandardButtons(QMessageBox.Close | QMessageBox.Save | QMessageBox.Cancel)
        msg.setWindowTitle("Data will be lost")
        btn_clicked = msg.exec_()

        # Here i can do this.
        if btn_clicked == QMessageBox.Save:
            print("Close.. After Saving...")
        elif btn_clicked == QMessageBox.Close:
            print("Close.. Without saving")
        else:
            print("Cancel.. Don't exit the program")


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    win = Window()
    win.resize(200, 200)
    win.show()
    sys.exit(app.exec_())

CodePudding user response:

I've found the solution and it worked with me by using a custom signal and slot, but still not sure if it is good or not. waiting for approval and then I can mark this solution as an accepted one.

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class CustomDialog(QDialog):
    # Create a signal
    signal = pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Data will be lost")
        label = QLabel("Are you sure you want close the app before saving?")
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.addButton(QDialogButtonBox.Save)
        self.buttonBox.addButton(QDialogButtonBox.Cancel)
        self.buttonBox.addButton(QDialogButtonBox.Close)

        layout = QVBoxLayout()
        layout.addWidget(label)
        layout.addWidget(self.buttonBox)
        self.resize(300, 100)
        self.setLayout(layout)

        # connect each button with custom slot
        self.buttonBox.button(QDialogButtonBox.Save).clicked.connect(lambda: self.customSlot(QDialogButtonBox.Save))
        self.buttonBox.button(QDialogButtonBox.Close).clicked.connect(lambda: self.customSlot(QDialogButtonBox.Close))
        self.buttonBox.button(QDialogButtonBox.Cancel).clicked.connect(lambda: self.customSlot(QDialogButtonBox.Cancel))

        # connect signal with buil-in function from QDialog (done())
        # This done function will return <int> value and close the dialog.
        self.signal.connect(self.done)

    def customSlot(self, button_id):
        # emit button's id
        self.signal.emit(button_id)


class Window(QWidget):
    def __init__(self):
        super().__init__()
        label = QLabel('Hello Dialog', self)
        open_dialog_button = QPushButton('Open Dialog', self)
        open_dialog_button.clicked.connect(self.showDialog)

        layout = QVBoxLayout()
        layout.addWidget(label)
        layout.addWidget(open_dialog_button)
        self.setLayout(layout)

    def showDialog(self):
        dialog = CustomDialog()
        btn_clicked = dialog.exec_()  # dialog exec returns button's id

        # Now you can use the following lines of code
        if btn_clicked == QDialogButtonBox.Save:
            print("Close.. After Saving...")
        elif btn_clicked == QDialogButtonBox.Close:
            print("Close.. Without saving")
        else:
            print("Cancel.. Don't exit the program")


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    win = Window()
    win.resize(200, 200)
    win.show()
    sys.exit(app.exec_())
  • Related