Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将信号连接到插槽会立即发出信号_Python_Pyqt_Python 3.3_Pyqt5 - Fatal编程技术网

Python 将信号连接到插槽会立即发出信号

Python 将信号连接到插槽会立即发出信号,python,pyqt,python-3.3,pyqt5,Python,Pyqt,Python 3.3,Pyqt5,我正在用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

我正在用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)
此代码使用供应商和模型填充组合框。供应商组合框在启动时填充。模型组合框中填充了每个供应商的不同数据。每次用户选择不同的供应商时,必须使用不同的列表更新模型组合框

应该发生什么:

调用PopulateVendorAndModelComboBox方法时,程序的第一部分将供应商列表放入供应商组合框中。然后将在currentTextChanged信号和_vendorChanged插槽之间建立连接。然后,最初应调用_vendorChanged函数来设置模型组合框。从那时起,每当用户选择新供应商时,都应该调用_vendorChanged函数

正在发生的事情:

当在currentTextChanged信号和_vendorChanged插槽之间建立连接时,立即调用_vendorChanged函数。它不应该立即调用_vendorChanged函数。我的任何其他信号/插槽连接都不会发生这种情况。执行_vendorChanged函数时没有出现错误,然后执行点返回到vendorComboBox.currentTextChanged.connect。。。。语句,我立即得到一个错误TypeError:参数1具有意外的类型“NoneType”

如果我注释掉建立连接的语句,程序将正常工作。供应商组合框中填充供应商,模型组合框中填充列表中第一个供应商的模型。这表明_vendorChanges代码工作正常


我有两个问题。为什么connect语句会导致立即执行_vendorChanged函数?错误消息的原因是什么?

该错误是由于尝试连接到函数调用的结果而导致的,在本例中,函数调用的结果是无,而不是函数对象本身。当然,这也解释了为什么函数会立即执行

您应该将函数调用包装在lambda中,如下所示:

    vendorComboBox.currentTextChanged.connect(
        lambda: _vendorChanged(vendorComboBox, dictVendors, modelComboBox))

基于Ekhumaro的答案,您还可以让信号将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)

希望有帮助

非常好的答案,但我想补充以下解释:

vendorComboBox.currentTextChanged.connect(_vendorChanged(vendorComboBox, dictVendors, modelComboBox))
和做同样的事

obj = _vendorChanged(vendorComboBox, dictVendors, modelComboBox)
vendorComboBox.currentTextChanged.connect(obj)

现在您应该看到obj不是一个函数,而是使用3个参数调用_vendorChanged函数的结果。这意味着您得到的印象是信号立即被触发,从而调用了您的函数,但实际上它只是您的函数按照指示执行。第二个问题是_vendorChanged没有返回任何内容,因此obj实际上没有。由于您试图将信号连接到None,因此会出现此错误。其他答案给出了解决方案

添加lambda解决了我的问题,但我不明白为什么。为什么我的语句试图连接函数调用的结果而不是函数本身?这和结束有关系吗?还是因为我写的东西被改变了?我的其他connect语句都不是这样的。我注意到,当我在这个connect语句上放置断点时,我的调试器说_vendorChanged是一个函数,而在其他connect语句中,调试器说我正在连接到绑定方法。我不明白为什么其他人在没有lambda的情况下工作,但这个不行。你的回答和@ekhumoro非常有用。你的简化了功能。我仍然坚持一件事。为什么消除vendorsDict和modelCBox允许我消除lambda?或者为什么要强迫我使用lambda?我可以将您的两个回复都标记为答案吗?这与函数是python中的对象这一事实有关。假设您使用def myFuncarg:return arg*2或与lambda:myFunc=lambda arg:arg*2相同的内容定义函数。。。在Python解释器中键入just myFunc时,它将返回或。这个函数对象还没有被调用,它只是一个函数的定义,它可以被存储、传递、重命名等等。
返回值通常不是函数,而是bool、int、string、list或None(如果没有return语句)。事实上,如果您主要编写返回其他函数的函数,那么您就是在实现函数编程。无论如何,信号必须连接到插槽,插槽必须是可调用的,基本上它必须是未调用的函数。这样,每当信号发出时,插槽就被称为。。。因此,对于checkbox.clicked.connectslot,当单击该框时,该插槽被称为类似于插槽。如果是复选框。单击[bool].connectslot,则如果选中该复选框,它将被称为slotTrue。lambda用于动态生成快速可调用函数,其优点是您可以将参数传递给另一个函数。这对于信号和插槽非常有用,因为它允许您将函数用作插槽,插槽接受的参数多于信号发出的参数。如果没有lambda,slot函数必须接受1或0个参数,这取决于您是否连接到携带数据的信号。对于lambda,lambda就像一个代理,只要接口提供信号需要0或1个输入,同时向函数提供附加参数。此外,lambda中的函数在lambda被调用之前不会被调用,就像函数定义的内容在函数被调用之前不会被执行一样。。。这些有意义吗?