問題描述
我正在使用 python 3.3.3 和 pyqt5 編寫程序.我已經連接了許多信號和插槽,沒有問題.這導致了一個問題.我的代碼如下:
I am writing a program with python 3.3.3 and pyqt5. I have connected many signals and slots with no problem. This one is causing a problem. My code follows:
def populateVendorAndModelComboBoxes(self, vendorComboBox, modelComboBox):
dictVendors = {}
#for rclass in sorted(list(directory.DRV_TO_RADIO.values())):
for rclass in list(directory.DRV_TO_RADIO.values()):
if not issubclass(rclass, chirp_common.CloneModeRadio) and
not issubclass(rclass, chirp_common.LiveRadio):
continue
if not rclass.VENDOR in dictVendors:
dictVendors[rclass.VENDOR] = []
dictVendors[rclass.VENDOR].append(rclass)
vendorComboBox.addItems(sorted(list(dictVendors)))
def _vendorChanged(vendorCBox, vendorsDict, modelCBox):
modelsList = vendorsDict[vendorCBox.currentText()]
added_models = []
modelCBox.clear()
for rclass in modelsList:
if rclass.MODEL not in added_models:
added_models.append(rclass.MODEL)
print("adding to modelCB")
modelCBox.addItems(sorted(added_models))
print("Done adding to modelCB")
vendorComboBox.currentTextChanged.connect(_vendorChanged(vendorComboBox, dictVendors, modelComboBox))
_vendorChanged(vendorComboBox, dictVendors, modelComboBox)
此代碼使用供應商和模型填充組合框.供應商組合框在啟動時填充.模型組合框填充了每個供應商的不同數據.每次用戶選擇不同的供應商時,必須使用不同的列表更新模型組合框.
This code populates comboboxes with vendors and models. The vendor combobox is populated at startup. The model combobox is filled with different data for each vendor. Every time the user picks a different vendor, the model combobox must be updated with a different list.
應該發生什么:
當調用方法 populateVendorAndModelComboBoxes 時,程序的第一部分將供應商列表放入供應商組合框中.然后將在 currentTextChanged 信號和 _vendorChanged 插槽之間建立連接.然后應該首先調用 _vendorChanged 函數來設置模型組合框.從那時起,每當用戶選擇新的供應商時,都應該調用 _vendorChanged 函數.
When the method populateVendorAndModelComboBoxes is called, the first part of the program puts the vendor list in the vendor combobox. Then a connection will be made between the currentTextChanged signal and the _vendorChanged slot. Then the _vendorChanged function should be initially called to setup the Model combobox. From then on, the _vendorChanged function should be called whenever the user picks a new vendor.
發生了什么:
當 currentTextChanged 信號和 _vendorChanged 槽建立連接時,立即調用 _vendorChanged 函數.它不應立即調用 _vendorChanged 函數.我的任何其他信號/插槽連接都不會發生這種情況._vendorChanged 函數執行沒有錯誤,然后執行點返回到 vendorComboBox.currentTextChanged.connect.... 語句,我立即收到錯誤 TypeError: argument 1 has unexpected type 'NoneType'.
When the connection is made between the currentTextChanged signal and the _vendorChanged slot, the _vendorChanged function is immediately called. It should not immediately call the _vendorChanged function. This does not happen with any of my other signal / slot connections. The _vendorChanged function is executed with out error, then the execution point drops back to the vendorComboBox.currentTextChanged.connect.... statement and I immediately get an error TypeError: argument 1 has unexpected type 'NoneType'.
如果我注釋掉建立連接的語句,程序就可以正常工作.供應商組合框填充了供應商,模型組合框填充了列表中第一個供應商的模型.這表明 _vendorChanges 代碼工作正常.
If I comment out the statement that makes the connection, the program works without error. The vendor combobox is filled with vendors and the model combobox is filled with models of the first vendor in the list. That indicates that the _vendorChanges code is working properly.
我有兩個問題.為什么 connect 語句會導致 _vendorChanged 函數立即執行?錯誤信息的原因是什么?
I have two questions. Why does the connect statement cause the _vendorChanged function to be immediately executed? What is the cause of the error message?
推薦答案
基于 ekhumoro 的回答,您還可以讓信號將 currentText 傳遞給 lambda 函數.這意味著您只需將文本傳遞給函數,而不必稍后再獲取 currentText.
Building on ekhumoro's answer, you could also let the signal pass the currentText to the lambda function. This means you would just pass the text into the function and not have to get the currentText later.
def _vendorChanged(vendorText, vendorsDict, modelCBox):
modelsList = vendorsDict[vendorText]
added_models = []
modelCBox.clear()
for rclass in modelsList:
if rclass.MODEL not in added_models:
added_models.append(rclass.MODEL)
print("adding to modelCB")
modelCBox.addItems(sorted(added_models))
print("Done adding to modelCB")
vendorComboBox.currentTextChanged[str].connect(
lambda vendorText: _vendorChanged(vendorText, dictVendors, modelComboBox))
另外,如果您不需要在每次發出信號時根據 lambda 函數的當前范圍更新對 dictVendors 和 modelComboBox 的引用,您可以將它們排除在參數列表之外,讓 _vendorChanged 函數簡單從它的父范圍繼承它們(這與 lambda 的父范圍相同......所以我不確定有什么區別......).這樣做的吸引力在于您不再需要 lamda 為信號提供可調用的...您可以直接給它 _vendorChanged 函數:
Also, if you don't need the references to dictVendors and modelComboBox to update based on the current scope of the lambda function every time the signal is emitted, you could leave them out of the parameter list and let the _vendorChanged function simply inherit them from it's parent scope (which is the same as the lambda's parent scope... so I'm not sure there's be any difference...). The appeal of this is that you no longer need the lamda to provide the signal with a callable... you can give it the _vendorChanged function directly:
def _vendorChanged(vendorText):
modelsList = dictVendors[vendorText]
added_models = []
modelComboBox.clear()
for rclass in modelsList:
if rclass.MODEL not in added_models:
added_models.append(rclass.MODEL)
print("adding to modelCB")
modelComboBox.addItems(sorted(added_models))
print("Done adding to modelCB")
vendorComboBox.currentTextChanged[str].connect(_vendorChanged)
希望有幫助!
這篇關于將信號連接到插槽立即導致信號被發射的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!