我正在用python 3.3.3和pyqt5编写程序。我连接了很多信号和插槽没有问题。这个问题导致了问题。我的代码如下:
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)
此代码使用供应商和模型填充组合框。供应商组合框在启动时填充。模型组合框填充了每个供应商的不同数据。每次用户选择不同的供应商时,必须使用不同的列表更新模型组合框。
会发生什么:
当调用方法populateVendorAndModelComboBoxes时,程序的第一部分将供应商列表放入供应商组合框中。然后将在currentTextChanged信号和_vendorChanged插槽之间建立连接。然后应该首先调用_vendorChanged函数来设置Model组合框。从那时起,只要用户选择新的供应商,就应该调用_vendorChanged函数。
发生了什么:
当currentTextChanged信号和_vendorChanged插槽之间建立连接时,会立即调用_vendorChanged函数。它不应该立即调用_vendorChanged函数。任何我的其他信号/插槽连接都不会发生这种情况。 _vendorChanged函数执行时没有输出错误,然后执行点回退到vendorComboBox.currentTextChanged.connect ....语句,我立即得到一个错误TypeError:参数1有意外类型'NoneType'。
如果我注释掉了建立连接的语句,程序就会正常运行。供应商组合框由供应商填充,模型组合框填充了列表中第一个供应商的模型。这表明_vendorChanges代码工作正常。
我有两个问题。为什么connect语句导致_vendorChanged函数立即执行?错误消息的原因是什么?
答案 0 :(得分:0)
错误是由于尝试连接到函数调用的结果(在本例中为None
)而不是函数对象本身引起的。当然,这也解释了为什么函数立即执行。
您应该将函数调用包装在lambda
中,如下所示:
vendorComboBox.currentTextChanged.connect(
lambda: _vendorChanged(vendorComboBox, dictVendors, modelComboBox))
答案 1 :(得分:0)
在ekhumoro的回答基础上,您还可以让信号将currentText传递给lambda函数。这意味着您只需将文本传递给函数,而不必在以后获取currentText。
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函数:
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)
希望有所帮助!
答案 2 :(得分:0)
优秀的答案,但只是想添加这个解释:
做
vendorComboBox.currentTextChanged.connect(_vendorChanged(vendorComboBox, dictVendors, modelComboBox))
与做
相同obj = _vendorChanged(vendorComboBox, dictVendors, modelComboBox)
vendorComboBox.currentTextChanged.connect(obj)
现在您应该看到obj
不是函数,而是使用3个参数调用_vendorChanged
函数的结果。这意味着你得到信号立即触发的印象,从而调用你的函数,但事实上它只是你的函数按照指示执行。第二个问题是_vendorChanged
没有返回任何东西,所以obj实际上是None。由于您尝试将信号连接到None,因此会出现此错误。解决方案在其他答案中给出。