2017-02-25 116 views
0

我需要爲一個類創建一個用戶界面,該類通過一組變量進行一些計算。代碼大致看起來像這樣:通過函數名稱訪問實例變量

class MainWindow: 
    def __init__(self): 
     pulse = Pulse() 

     self.var1_lineEdit.textEdited.connect(self.set_attribute(pulse, "var1", new_value)) 
     self.var2_lineEdit.textEdited.connect(self.set_attribute(pulse, "var2", new_value)) 
     self.var3_lineEdit.textEdited.connect(self.set_attribute(pulse, "var3", new_value)) 
     .... 

    def set_attribute(pulse, var_name, value): 
     # get value from line edit 
     # update value in pulse 
     # update other calculations 

class Pulse: 
    def __init__(self): 
     var1 = 1 
     var2 = 2 
     var3 = 3 
     .... 

我在這裏的問題是如何編寫set_attribute。有沒有辦法通過傳遞名稱作爲函數參數來訪問另一個類的單個變量?我想避免爲每個變量定義一個新函數。

還是有更簡單的方法來做到這一點?我不太熟悉OOP和UI編碼的正確方法。你提出的

+1

看起來你只是想要內置['setattr'](https://docs.python.org/3/library/functions.html#setattr)函數。 – jonrsharpe

+0

如果我正確理解了@ waterboy5281,那會比這更復雜。我試圖將多個信號連接到一個插槽,根據信號發射器 – MisterTea

回答

1

編輯

信號/槽連接,將讓你陷入困境。使用connect函數將信號連接到插槽,該函數接受可調用的python作爲其參數 - 而不是函數調用本身。這就是

widget.textChanged.connect(self.set_attribute) # right syntax 
widget.textChanged.connect(self.set_attribute()) # wrong syntax 

那麼你怎麼告訴set_attribute該怎麼做? ekhumoro通知我我的方式錯誤重新:使用QSignalMapper。這是一種過時的技術。最好簡單地使用lambda函數(或partials)來獲得所需的效果。

我更新了使用的lambdas

在該演示的目的演示,我創建了一個簡單的QMainWindow兩個QLineEdit部件和一個QPushButton

# file ui_main.py 
from PyQt5 import QtCore, QtGui, QtWidgets 

class Ui_MainWindow(object): 
    def setupUi(self, MainWindow): 
     MainWindow.setObjectName("MainWindow") 
     MainWindow.resize(359, 249) 
     self.centralwidget = QtWidgets.QWidget(MainWindow) 
     self.centralwidget.setObjectName("centralwidget") 
     self.formLayoutWidget = QtWidgets.QWidget(self.centralwidget) 
     self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 351, 51)) 
     self.formLayoutWidget.setObjectName("formLayoutWidget") 
     self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget) 
     self.formLayout.setObjectName("formLayout") 
     self.configParam1Label = QtWidgets.QLabel(self.formLayoutWidget) 
     self.configParam1Label.setObjectName("configParam1Label") 
     self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.configParam1Label) 
     self.configEntry = QtWidgets.QLineEdit(self.formLayoutWidget) 
     self.configEntry.setObjectName("configEntry") 
     self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.configEntry) 
     self.configParam2Label = QtWidgets.QLabel(self.formLayoutWidget) 
     self.configParam2Label.setObjectName("configParam2Label") 
     self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.configParam2Label) 
     self.configEntry2 = QtWidgets.QLineEdit(self.formLayoutWidget) 
     self.configEntry2.setObjectName("configEntry2") 
     self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.configEntry2) 
     self.pulseButton = QtWidgets.QPushButton(self.centralwidget) 
     self.pulseButton.setGeometry(QtCore.QRect(130, 140, 75, 23)) 
     self.pulseButton.setObjectName("pulseButton") 
     MainWindow.setCentralWidget(self.centralwidget) 

     self.retranslateUi(MainWindow) 
     QtCore.QMetaObject.connectSlotsByName(MainWindow) 

    def retranslateUi(self, MainWindow): 
     _translate = QtCore.QCoreApplication.translate 
     MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) 
     self.configParam1Label.setText(_translate("MainWindow", "Config Param 1")) 
     self.configParam2Label.setText(_translate("MainWindow", "Config Param 2")) 
     self.pulseButton.setText(_translate("MainWindow", "GetPulse")) 

在另一個文件中,部分進口後,確定Pulse --a簡單的類,它包含兩個屬性

# file main.py 
from PyQt5.QtCore import (QSignalMapper, pyqtSlot) 
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMessageBox) 

from ui_main import Ui_MainWindow 

class Pulse: 
    def __init__(self): 
     self.param_one = None 
     self.param_two = None 

現在,定義MainWindow,設置它的UI,給它一個Pulse

class MainWindow(QMainWindow): 
    def __init__(self, parent=None): 
     super(MainWindow, self).__init__(parent) 

     self.pulse = Pulse() 

     self.ui = Ui_MainWindow() 
     self.ui.setupUi(self) 

     self.widget_one = self.ui.configEntry 
     self.widget_two = self.ui.configEntry2 
     self.pulse_button = self.ui.pulseButton 

     self.widget_one.textChanged.connect(lambda: self.widget_handler('param_one', self.widget_one.text())) 
     self.widget_one.textChanged.connect(lambda: self.widget_handler('param_two', self.widget_two.text())) 

    def widget_handler(self, attr, value): 
     setattr(self.pulse,attr,value) 

    def handler(self, idx): 
     widget, attr = self.attribute_widget_list[idx] 
     widget_value = widget.text() 
     setattr(self.pulse,attr,widget_value) 

setattr相當於例如self.pulse.param_one = widget_value

爲了證明它的工作原理,讓我們使用的是QPushButton探測的Pulse狀態:

@pyqtSlot() 
    def on_pulseButton_clicked(self): 
     message = QMessageBox() 
     message.setText("{} - {}".format(self.pulse.param_one, self.pulse.param_two)) 
     message.exec() 

這裏我使用的是不同的信號/插槽連接方案,你可以讀到here

以下是我們如何運行該腳本:

if __name__ == '__main__': 
    import sys 

    app = QApplication(sys.argv) 
    window = MainWindow() 
    window.show() 
    sys.exit(app.exec_()) 

希望幫助!

+0

得出不同的結果,這要感謝關於連接功能的提示。與此同時,我編寫了一個函數,它可以盲目地更新每個編輯行更改的每個屬性,它可以完成這項工作,但它很瑣碎。您的解決方案看起來非常有趣,一旦我獲得了我的ui的第一個版本,我會嘗試一下。 – MisterTea

+1

這太過於複雜。標準習慣用法是使用'lambda'或'partial':例如'widget.signal.connect(lambda:func(arg1,arg2))'。 – ekhumoro

+0

謝謝,@ekhumoro。我更新了演示以使用lambdas。我不確定爲什麼我曾經想過QSignalMapper是最好的選擇。 – Crispin