PyQt4:创建一个返回参数的自定义对话框

12 投票
2 回答
30240 浏览
提问于 2025-04-16 16:16

我正在尝试为我的图形用户界面(GUI)添加一个自定义对话框,用户可以通过这个对话框设置一些参数。理想情况下,我想使用QtDesigner来创建这个自定义对话框。下面是通过pyuic4从QtDesigner生成的对话框代码。

from PyQt4 import QtCore, QtGui

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(508, 300)
        self.buttonBox = QtGui.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(150, 250, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.label = QtGui.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(10, 120, 181, 31))
        font = QtGui.QFont()
        font.setPointSize(16)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.sl_value = QtGui.QSlider(Dialog)
        self.sl_value.setGeometry(QtCore.QRect(220, 120, 161, 31))
        self.sl_value.setOrientation(QtCore.Qt.Horizontal)
        self.sl_value.setObjectName("sl_value")
        self.ed_value = QtGui.QLineEdit(Dialog)
        self.ed_value.setGeometry(QtCore.QRect(400, 120, 41, 31))
        font = QtGui.QFont()
        font.setPointSize(16)
        self.ed_value.setFont(font)
        self.ed_value.setObjectName("ed_value")
        self.retranslateUi(Dialog)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), Dialog.accept)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)


    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
        self.label.setText(QtGui.QApplication.translate("Dialog", "Set example value:", None, QtGui.QApplication.UnicodeUTF8))

这个代码保存在Sub2.py文件中。然后,在我的主Python文件里,我添加了

from Sub2 import Ui_Dialog

我创建了一个新的类,叫做StartSub2,代码如下

class StartSub2(QtGui.QDialog):
    def __init__(self,parent=None):
        QtGui.QDialog.__init__(self,parent)
        self.ui = Ui_Dialog
        self.ui.setupUi(self)

最后,在我的主GUI里,有一个函数,代码如下,应该用来启动这个对话框

def exampleSubGui(self):
    dialog = StartSub2(self)
    result = dialog.exec_()

请注意,这个对话框还没有完成。一旦我解决了如何启动它的问题,我会为滑块和编辑框添加信号/槽连接。此外,如果我理解得没错,我还需要重载accept()方法,以返回用户的输入。

我遇到的第一个问题是StartSub2__init__方法。我得到了以下错误:

TypeError: unbound method setupUi() must be called with Ui_Dialog instance as
first argument (got StartSub2 instance instead)

我试图采取与主GUI相同的方法,主GUI使用了以下代码

class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

但这个代码并没有抱怨setupUi()接收了一个StartQT4实例,而不是Ui_MainWindow实例。有没有人能解释一下我想做的事情的正确方法?或者能否给我指个清晰的例子或参考?如果你需要更多信息或澄清,请告诉我。

2 个回答

2

我想分享一下如何设置一个自定义对话框,并且可以返回值(不回答具体的代码问题,那个Whatang已经解决了)。

我觉得创建一个简单的对话框类会更清晰,这个类里面有一个类方法,可以根据需要返回不同的东西。我最近经常这样做!这个类方法的作用是构造对话框类的一个实例,并从这个实例中返回一些对象(在这个例子中是布尔值 ok),这在某种程度上可以看作是工厂方法(我理解的就是这样,毕竟我对面向对象编程还比较陌生)。

下面是一个非常简化的对话框示例。你可以很容易地根据需要扩展这个对话框类:

class OkDialog(QtGui.QDialog):
    def __init__(self, parent):
        super(OkDialog, self).__init__(parent)

        self.ok = False

        self.btn_ok = QtGui.QPushButton("Ok", self)
        self.btn_ok.clicked.connect(self.button_press)
        self.btn_cancel = QtGui.QPushButton("Cancel", self)
        self.btn_cancel.clicked.connect(self.button_press)
        self.btn_cancel.move(80, 0)

    def button_press(self):
        if self.sender() == self.btn_ok:
            self.ok = True
        self.close()

    @classmethod
    def isOkay(cls, parent):
        dialog = cls(parent)
        dialog.exec_()
        return dialog.ok

最棒的是,当你需要构造这个对话框的时候,只需要一行代码 OkDialog.isOkay(parent)。接下来把它整合成一个完整的示例:

import sys
from PyQt4 import QtCore, QtGui

class OkDialog(QtGui.QDialog):
    def __init__(self, parent):
        super(OkDialog, self).__init__(parent)

        self.ok = False

        self.btn_ok = QtGui.QPushButton("Ok", self)
        self.btn_ok.clicked.connect(self.button_press)
        self.btn_cancel = QtGui.QPushButton("Cancel", self)
        self.btn_cancel.clicked.connect(self.button_press)
        self.btn_cancel.move(80, 0)

    def button_press(self):
        if self.sender() == self.btn_ok:
            self.ok = True
        self.close()

    @classmethod
    def isOkay(cls, parent):
        dialog = cls(parent)
        dialog.exec_()
        return dialog.ok

class Ui_Dialog(QtGui.QDialog):
    def __init__(self):
        super(Ui_Dialog, self).__init__()

        button = QtGui.QPushButton("Launch custom dialog", self)
        button.pressed.connect(self.launch_dialog)

    def launch_dialog(self):
        print OkDialog.isOkay(self)

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Ui_Dialog()

    ex.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
21
class StartSub2(QtGui.QDialog, Ui_Dialog):
    def __init__(self,parent=None):
        QtGui.QDialog.__init__(self,parent)
        self.setupUi(self)

这应该能解决你第一个问题,也就是让对话框初始化。

为了获取信息,我通常会在 StartSub2 中添加一个叫 getValues 的方法,也就是这样:

def getValues(self):
    return somethingUseful

然后执行

dlg = StartSub2()
if dlg.exec_():
    values = dlg.getValues()
    # Do stuff with values

撰写回答