1

我正在开发一个 Python 应用程序,该应用程序从一个包含大量来源记录的大文件中绘制数据。我试图为用户提供的选项之一是,如果需要,可以选择仅绘制这些源的子集。我首先阅读文件,找出有多少独特的东西,然后为每个文件创建一个 QCheckBox(),以它的源命名(每个源都有一个唯一的名称)来实现这一点。在这种特殊情况下,数据文件被解析成一个巨大的字典,其中的键是唯一的来源。我想为每个复选框连接到 stateChange() 事件,然后在未选中该框时禁用该源的绘图。在这种情况下,当检查/未选中该框时,将从源列表中添加/删除源。

最初,创建的窗口看起来是正确的,每个按钮都被适当地命名。每次按下按钮时,btnstate() 都应该简单地打印与该按钮关联的文本。如果您可以显式定义每个按钮,则该方法有效,如示例中的单选按钮所示。如果您单击其中任何一个,您将获得打印的按钮的正确名称,但是当取消选中/重新选中任何复选框时,btnstate 会打印“test4”。

我究竟做错了什么?

这是代码(源更改为虚拟值):

import sys
from PyQt4.QtGui import *

def btnstate(b):
    print b.text()

def main():
   app = QApplication([])
   widget = QWidget()
   layout = QVBoxLayout()
   widget.setLayout(layout)
   radio_layout = QHBoxLayout()
   checkbox_layout = QHBoxLayout()

   #setup radio buttons for config pop-up window
   r1 = QRadioButton("Page Count")
   r2 = QRadioButton("Date")
   r1.toggled.connect(lambda:btnstate(r1))
   r2.toggled.connect(lambda:btnstate(r2))
   radio_layout.addWidget(r1)
   radio_layout.addWidget(r2)

   cbs = []
   for idx, serial in enumerate(["test1", "test2", "test3", "test4"]):
      temp = QCheckBox(serial)
      temp.setText(serial)
      temp.setChecked(True)
      checkbox_layout.addWidget(temp)
      temp.stateChanged.connect(lambda:btnstate(temp))
      cbs.append(temp)

  layout.addLayout(radio_layout)
  layout.addLayout(checkbox_layout) 
  widget.show()
  sys.exit(app.exec_())


if __name__ == '__main__':
  main()
4

1 回答 1

0

我认为发生这种情况的原因与 Python 如何在循环内绑定和取消绑定引用有关。因为temp在每次迭代中都被重新定义,所以槽也被更新,因此它有效地为每个按钮调用相同的 lambda。这有点牵强,因为我对 Python 引用细节的理解不是很深。但是我知道Python 绑定到Qt 在Python 的引用和垃圾收集方面存在很多问题,例如在删除小部件时,因为Qt 对象层次结构并不完全适用于Python。

无论如何,更实际的是,有一个非常简单的解决方法。您可以使用该functools.partial方法将部分函数定义为插槽,而不是 lambda。将按钮绑定为第一个对象,使按钮状态(作为信号参数发出)未绑定。像这样:

import functools

def btnstate(button, state):
    print button.text()

然后在循环中:

for idx, serial in enumerate(['test1', 'test2', 'test3', 'test4']):
    temp = QCheckBox(serial)
    checkbox_layout.addWidget(temp)
    temp.stateChanged.connect(functools.partial(btnstate, serial))

运行此程序,我现在可以在选中/取消选中每个框时打印正确的标签。

编辑:

有关Python 引用计数与 Qt 对象层次结构的奇怪交互方式的另一个示例,请参阅这篇文章。

于 2017-01-26T02:10:50.600 回答