簡體   English   中英

在 Qt (PyQt5) 中創建自定義信號/插槽

[英]Creating a custom signal/slot in Qt (PyQt5)

我是使用 Qt 和一般構建 GUI 的完整初學者,所以如果這是一個愚蠢的問題,但我在互聯網上找不到答案,我深表歉意。 我希望你能幫助我解決幾個問題:


首先,我使用 Qt Designer 創建了一個 GUI,我遇到了“接線”的問題。 我有一個帶有多種選項的組合框,我想做的是在框中選擇更改一堆行編輯框中的文本 問題是,當組合框的textActivated()信號被發送到行編輯的setText()槽時,行編輯被組合框中的文本填充。

下面我舉一個小例子來說明我的意思。 此組合框具有值ABC 選擇一個選項后,該字母會出現在框中。 我想要做的是讓組合框的每個條目成為一個值的“鍵” ,所以如果選擇了例如A ,那么行編輯將用選項 1或類似的東西填充。 我想這樣做的原因是因為組合框會根據輸入設置一堆默認參數,然后用戶可以根據需要調整這些值。

Window截圖

在此處輸入圖像描述

我知道我需要修改的線路/負責信號/插槽連接的線路是

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

但我真的不明白當.connect 是一個實例 function 時,我將如何傳遞 combobox 的值。

有誰知道如何使用自定義功能/插槽來做到這一點? 完整的代碼在這篇文章的底部。


其次,一個相關的問題,為什么window的__init__() function中的這些信號/插槽go? app.exec_()是否連續運行__init__() 實例化 object 然后在應用程序循環中運行“更新” function 不是更明智嗎?


提前致謝!



完整代碼

# -*- 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_())

更新

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_())

你在某處做一個字典。 你總是參考它。 我不知道您將鍵和值連接擴展了多長時間,但是您現在可以直接在任何地方設置相同的鍵和值。它很冗長,您最好總是盡可能多地從一個 object 獲取密鑰。 如果您這樣做,無論您在字典中添加新的鍵和值,更改都會反映而不會更改其他代碼。 當你想擴展你的key&value時,你所要做的就是只重寫一次dic的數據。 幸運的是,dict 可以保存鍵的順序... python3.6您可以像列表一樣使用鍵。 請 append 'D': 'You choose 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 (信號)與lineEdit.setText (插槽)連接起來,所以,如果您在 object 發出時設置 currentText(),setText 會捕獲 object。如果您將信號連接到三個lineedit.setText ,所有的 lineedits 通過相同的信息設置文本。

發射前,除了默認設置外,您必須建立連接。

如果我的答案是您想要的,我認為您不需要制作自定義信號和插槽。

二、一個相關的問題,為什么這些signal/slots go在init () function的window中? app.exec_() 是否連續運行init ()? 實例化 object 然后在應用程序循環中運行“更新” function 不是更明智嗎?

您可以從init () 連接信號/插槽。 但是在那個地方建立連接通常非常方便。 在大多數情況下,沒有機會斷開連接。如果您不想連接,您可以使用blockSignals()方法阻止連接。

因此,為了證明這一點,您可以嘗試在某處編寫測試代碼以在__init__之后建立連接。 例如,用於制作信號&槽的信號&槽。

app.exec_()運行一個循環,但不會一遍又一遍地運行__init__() app.exec_()正在等待用戶輸入,eventHandler,例如keyPressEventmousePressEvent 特別是用於顯示 GUI 的paintEvent() init只被調用一次。 它的變量被分配到您的計算機地址 memory 中。

一遍遍地調用init意味着memory被一遍遍地重寫。Memory主要是為了避免這種浪費。

如果您在使用您的應用程序后通過keyPressEventmousePressEvent或 signal&slot 機制更改變量的內容,則將 memory 的分配地址改寫為其他內容。

我認為更新是在更改之后調用的。 這是為了根據新變量更新 GUI 表面信息。

感謝@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')

其中,在選擇組合框項目時,一些文本(不是組合框中的選項之一)會顯示在行編輯中。 上述代碼適用於 window 的初始化,但在做出新選擇時無效。


完整代碼在這里:

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_())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM