【问题标题】:Creating a custom signal/slot in Qt (PyQt5)在 Qt (PyQt5) 中创建自定义信号/槽
【发布时间】:2020-10-22 11:43:42
【问题描述】:

我是一个使用 Qt 和一般构建 GUI 的完整初学者,所以如果这是一个愚蠢的问题,但我在互联网上找不到答案,我深表歉意。我希望你能帮助我解决几个问题:


首先,我使用 Qt Designer 创建了一个 GUI,但在“连接它”时遇到了问题。我有一个包含多种选项的组合框,我想做的是在框中选择更改一堆行编辑框中的文本。问题是,当组合框的textActivated()信号发送到行编辑的setText()槽时,行编辑被组合框中的文本填充。

下面我举一个小例子来说明我的意思。该组合框具有值 ABC。选择一个选项后,该字母会出现在框中。 我想要做的是让组合框的每个条目成为一个值的“键”,所以如果例如A 被选中,然后用 Option 1 或类似的东西填充行编辑。我想这样做的原因是因为组合框会根据输入设置一堆 default 参数,然后用户可以根据需要tweak .

Screenshot of Window

我知道我需要修改的线路/负责信号/插槽连接的线路是

self.comboBox.textActivated['QString'].connect(self.lineEdit.setText)

但我真的不明白当 .connect 是一个实例函数时我将如何传递组合框的值。

有谁知道如何使用自定义函数/插槽来做到这一点?完整的代码在这篇文章的底部。


第二,一个相关的问题,为什么这些信号/槽会进入窗口的__init__()函数? app.exec_() 是否连续运行 __init__()?实例化一个对象,然后在应用循环中运行一个“更新”函数不是更明智吗?


提前致谢!



完整代码

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

# Form implementation generated from reading ui file 'practice.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(493, 124)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.comboBox = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox.setObjectName("comboBox")
        self.comboBox.addItem("")
        self.comboBox.addItem("")
        self.comboBox.addItem("")
        self.horizontalLayout.addWidget(self.comboBox)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName("lineEdit")
        self.horizontalLayout.addWidget(self.lineEdit)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 493, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        self.comboBox.textActivated['QString'].connect(self.lineEdit.setText)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.comboBox.setItemText(0, _translate("MainWindow", "A"))
        self.comboBox.setItemText(1, _translate("MainWindow", "B"))
        self.comboBox.setItemText(2, _translate("MainWindow", "C"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python qt user-interface pyqt qt-designer


    【解决方案1】:

    更新

    from PyQt5 import QtCore, QtGui, QtWidgets 
    #here you make dict in advance.   
    dic = {'A':'You choose A',
           'B':'You choose B',
           'C':'You choose C'}  
    # a list of the dict key. #[*dic] is also ok instead of lis
    lis = dic.keys() 
    class Ui_MainWindow(object):
    
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(493, 124)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.comboBox = QtWidgets.QComboBox(self.centralwidget)
            self.comboBox.setObjectName("comboBox")
            #addItems is for multiple items.
            self.comboBox.addItems(lis)
            self.horizontalLayout.addWidget(self.comboBox)
            self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
            self.lineEdit.setObjectName("lineEdit")
            self.horizontalLayout.addWidget(self.lineEdit)
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 493, 21))
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
            self.retranslateUi(MainWindow)
            self.comboBox.activated['QString'].connect(self.new_selection)
            #I think it is not bothered with .emit of my first answer.
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
            # number and value you can use enumerate func.
            for num, key in enumerate(lis):
             
                self.comboBox.setItemText(num, _translate("MainWindow", key))
         
    
        def new_selection(self):
            self.lineEdit.setText(dic[self.comboBox.currentText()])
           
    
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)  # Whole application
        MainWindow = QtWidgets.QMainWindow()  # create the actual window
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()  # Actually show the window
        sys.exit(app.exec_())
    

    你在某个地方做了一个 dict。 你总是参考它。 我不知道您将键和值连接扩展了多长时间,但是您现在直接在任何地方设置了相同的键和值。它很冗长,您最好总是尽可能多地从一个对象中获取键。如果您这样做,无论您在字典中添加新的键和值,更改都会反映而不会更改其他代码。 当你想扩展你的key&value时,你只需要重写dic的数据一次。 幸运的是,dict 可以保存来自 ...python3.6 的键的顺序 您可以使用列表等键。 请附加“D”:“您选择 D”或其他数据并尝试一下! 很高兴我的回答是你想要的。


    简单地说,你能通过这段代码达到你的目的吗?

    我从你的问题中了解到的是第一次设置lineedit上的第一项。

    我不知道你实际上想要设置什么,但是,从 (PyQt5.14) 开始的 textActivated() (我可以激活(),因为我的版本是 5.9.x)...

    `signal.connect(somthing slot)` means that make a connection between signal & slot.
    
    `signal.emit(object)` means that to emit the connected signal.
    

    因为你已经连接了textActivated(signal) 和lineEdit.setText(slot),所以,如果你在对象发出的时候设置了currentText(),那么setText 就会捕捉到对象。如果你把信号连接到三个lineedit.setText,所有的 lineedits 都用相同的信息设置文本。

    在发射之前,您必须建立一个连接,默认设置除外。

    如果我的答案是您想要的,我认为您不需要制作自定义信号和插槽。

    其次,一个相关的问题,为什么这些信号/槽会进入窗口的init()函数? app.exec_() 是否连续运行 init()?实例化一个对象然后在应用循环中运行一个“更新”函数不是更明智吗?

    您可以通过 init() 连接信号/插槽。 但是在那个地方建立连接通常非常方便。 大多数情况下是没有机会断开连接的。如果不想连接,可以使用blockSignals()方法阻止连接。

    因此,为了证明这一点,您可以尝试在某处编写测试代码以在__init__ 之后建立连接。 比如一个signal&slot,用于制作signal&slot。

    app.exec_() 运行一个循环,但不会一遍又一遍地运行__init__()app.exec_() 正在等待用户输入,eventHandler,例如,keyPressEventmousePressEvent。 特别是 paintEvent() 用于显示 GUI。 init 只被调用一次。它的变量被分配到您计算机的内存地址中。

    一遍又一遍地调用init意味着内存被一遍遍地重写。内存主要是为了避免这种浪费。

    如果你通过keyPressEventmousePressEvent,或者signal&slot机制在你的应用程序使用后改变了变量的内容,那就是你把分配的内存地址改写成别的东西了。

    我认为更新是在更改之后调用的。 这是为了根据新变量更新 GUI 表面信息。

    【讨论】:

    • 您好,Haru,感谢您的回复。看来我无法在此评论中添加代码,所以请查看我的其他答案
    【解决方案2】:

    感谢@Haru 的帮助,我想通了:
    这是相关代码:

    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            ...
            ...
            ...
            self.comboBox.textActivated['QString'].connect(self.new_selection)
    
    
        def new_selection(self):
            if self.comboBox.currentText() == 'A':
                self.lineEdit.setText('You chose B')
            elif self.comboBox.currentText() == 'B':
                self.lineEdit.setText('You chose B')
            elif self.comboBox.currentText() == 'C':
                self.lineEdit.setText('You chose C')
    

    在选择组合框项目时,某些文本(不是组合框中的选项之一)会显示在行编辑中。上面的代码适用于窗口的初始化,但不适用于进行新的选择。


    完整代码在这里:

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(493, 124)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.comboBox = QtWidgets.QComboBox(self.centralwidget)
            self.comboBox.setObjectName("comboBox")
            self.comboBox.addItem("")
            self.comboBox.addItem("")
            self.comboBox.addItem("")
            self.horizontalLayout.addWidget(self.comboBox)
            self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
            self.lineEdit.setObjectName("lineEdit")
            self.horizontalLayout.addWidget(self.lineEdit)
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 493, 21))
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
            self.retranslateUi(MainWindow)
            self.comboBox.textActivated['QString'].connect(self.new_selection)
    
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
            self.comboBox.setItemText(0, _translate("MainWindow", "A"))
            self.comboBox.setItemText(1, _translate("MainWindow", "B"))
            self.comboBox.setItemText(2, _translate("MainWindow", "C"))
    
        def new_selection(self):
    
            if self.comboBox.currentText() == 'A':
                self.lineEdit.setText('You chose B')
            elif self.comboBox.currentText() == 'B':
                self.lineEdit.setText('You chose B')
            elif self.comboBox.currentText() == 'C':
                self.lineEdit.setText('You chose C')
    
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)  # Whole application
        MainWindow = QtWidgets.QMainWindow()  # create the actual window
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()  # Actually show the window
        sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 2013-01-10
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      • 2016-07-17
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多