【问题标题】:QtCore.QObject.connect in a loop only affects the last instance循环中的 QtCore.QObject.connect 仅影响最后一个实例
【发布时间】:2013-10-30 21:49:54
【问题描述】:

我有一个循环。我创建了一个QCheckBox 并将其放入QTableWidget 单元格中,一切正常。在循环的每个步骤中,我为 myslot SLOT 调用了一个 connect 函数,但只应用了最后一个 QCheckBox 实例。我google了很多,发现很多人都有我的问题。我已经应用了他们的解决方案,但我的问题仍然存在。

for row in xrange(len(uniqueFields)):
    instance = QtGui.QCheckBox(uniqueFields[row], findInstance.tableWidget)
    print QtCore.QObject.connect(instance,
        QtCore.SIGNAL(_fromUtf8("stateChanged (int)")),
        lambda: findInstance.projectsInstance.myslot(
                    "TWCH", findInstance, instance.text(),
                    instance.checkState(), instance))
    findInstance.tableWidget.setRowCount(findInstance.tableWidget.rowCount() + 1)
    findInstance.tableWidget.setCellWidget(row, 0, instance)

注意:我的connect函数返回True

如何在枚举所有instances的循环中创建connect函数?

【问题讨论】:

    标签: c++ qt pyqt qtcore qt-signals


    【解决方案1】:

    问题是您正在使用lambda 创建一个函数,其中函数内的一些变量没有作为参数传递给函数。当执行 lambda 函数时,当发出信号时,它会及时使用那些变量的值(如instance)。需要明确的是,您创建的每个 lambda 函数都在运行时使用 instance 的值,而不是定义时间。所以instance 仅包含对我们循环的最后一次迭代中使用的对象的引用,这解释了您所看到的行为。

    可以在这里找到一些有用的信息(也可以阅读 cmets)http://eli.thegreenplace.net/2011/04/25/passing-extra-arguments-to-pyqt-slot/

    来自上述链接的cmets:

    您可以做的是让另一个函数生成 lambda,即 类似:

    def make_callback(param):   
            return lambda: self.on_button(param)
    

    在连接中,请致电make_callback(i)。然后一个不同的 lambda 是 为每次迭代创建。

    因此,您可能希望对此进行概括,并将instance 之类的内容传递给make_callback 函数,然后将您的lambda 定义放在make_callback 函数中。我会提供一个明确的例子,但正如另一个答案所说,您的格式似乎在您的问题中变得非常混乱,对于您的特定应用程序,我可能会弄错。如果您没有按照我所说的进行操作,请让您的问题中的代码更清晰,我将尝试创建一个示例!

    【讨论】:

      【解决方案2】:

      将循环变量放入默认参数中,如下所示:

      lambda state, instance=instance: findInstance.projectsInstance.myslot(
          "TWCH", findInstance, instance.text(), instance.checkState(), instance)
      

      这将为每个 lambda 提供其自己的 instance 变量的本地副本。

      编辑

      这是一个演示如何使用默认 lambda 参数的简单脚本:

      from PyQt4 import QtGui
      
      class Window(QtGui.QWidget):
          def __init__(self):
              QtGui.QWidget.__init__(self)
              layout = QtGui.QVBoxLayout(self)
              for index in range(4):
                  instance = QtGui.QCheckBox('Checkbox(%d)' % index, self)
                  instance.stateChanged.connect(
                      lambda state, instance=instance:
                          self.mySlot(instance.text()))
                  layout.addWidget(instance)
      
          def mySlot(self, text):
              print('clicked: %s' % text)
      
      
      if __name__ == '__main__':
      
          import sys
          app = QtGui.QApplication(sys.argv)
          window = Window()
          window.show()
          sys.exit(app.exec_())
      

      【讨论】:

      • 这不起作用,因为发出信号时没有参数传递给插槽。您需要创建一个不带参数的 lambda,但它仍然有自己的实例副本。因此,我的答案是您使用函数来制作 lambda
      • @three_pineapples。它工作得很好:请参阅我更新的答案以获取工作示例。正如我在原始答案中解释的那样,默认参数用于缓存循环变量,因此无需使用闭包(尽管这也可以)。
      • 啊,抱歉,我跳过了其中的instance=instance 部分(我刚刚阅读了instance)。你的方法比我的建议要干净得多,我将开始在我自己的代码中使用它
      【解决方案3】:

      我也有同样的问题,你应该使用functools.partial 比如:

      for key, val in a_DICT_THAT_YOU_STORED_YOUR_OBJECTS_AND_STRINGS:
          obj = partial(   findInstance.projectsInstance.myslot,arg1="TWCH",arg2=self,arg3=key,arg4=val.checkState() )
          QtCore.QObject.connect(val, QtCore.SIGNAL(_fromUtf8("stateChanged (int)")), obj)
      

      当然,argX 应该设置为你的函数名的实名。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-22
        • 2013-09-18
        • 1970-01-01
        • 2017-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多