【问题标题】:Passing Arguments with Newstyle signals in PyQT在 PyQT 中使用 Newstyle 信号传递参数
【发布时间】:2011-11-18 07:58:19
【问题描述】:

我在 PyQT 中使用一组动态创建的按钮时遇到了一些问题。

我正在使用一个列表来创建对应于不同值的按钮。因为每个按钮都不同,我需要让它们将参数传递给“Button Clicked”函数,分别标识它们自己,这样我就可以对它们执行不同的操作。这是我目前所拥有的:

for x in self.buttons:
    name = str(x)
    button = QtGui.QPushButton(Frame)
    button.setText(name)
    cp_result = self.changeProject(name)
    if cp_result is None:
        print 'changeProject(%s) is None!', name
    else:
        print 'changeProject(%s) is OK (%r)', name, cp_result
        #button.clicked.connect(cp_result)
    setattr(self, "btn_%s" % name, button)
    self.btnList.append(button)

def changeProject(self, name):
    for x in self.btnList:
        if x.isDown:
            #Change UI Frame to blahblah
    return 'A String'

与 Alex 合作,这是最新的代码,测试 changeProject 上的返回值,这显然不能是字符串,但我仍然需要确定在自动生成的按钮之间按下了哪个按钮。

当前错误:TypeError: connect() slot argument should be a callable or a signal, not 'str'

【问题讨论】:

  • 啊啊!数组是有史以来最基本的数据结构之一,甚至包含在最原始的语言中,但有些人没有使用它们,最终以一种慢得要命、非常不雅和愚蠢的方式复制它们(即,通过滥用 @987654323 @/exec)。另外,错误信息很清楚,不是吗? self.changeProject("x") 的结果是 None - 找出原因并修复它。
  • 我读到了关于寻找一种基于列表创建动态变量的方法,而 exec 似乎是一种流行的选择。有没有更好的办法?此外,self.changeProject("x") 的结果是一个字符串。
  • 真正的解决方案不是动态创建变量(在 99% 的情况下,我并不完全谴责它)。几乎总是,你真的想要一个映射(即 dict)。不仅快很多倍,而且方法正确,不可能与不相关的变量发生冲突,而且更容易跟踪。

标签: python pyqt signals


【解决方案1】:

您可以使用setattr 为对象动态添加属性

for x in buttons:
    name = str(x)
    button = QtGui.QPushButton(Frame)
    button.setText(name)
    button.clicked.connect(self.changeProject(name))
    setattr(self, "btn_%s" % name, button)

【讨论】:

  • 这有助于过度使用 exec 问题,但是关于连接的任何想法?即使设置了 setattr 位,错误仍然存​​在。
【解决方案2】:

错误消息告诉您的是,self.changeProject("%s") 替换为 %s 的值之一返回 None。大概您的意思是让该方法返回不同的东西?

当然,如果不查看代码,就无法进一步帮助您完成调试changeProject 的任务。但是,例如,您可以将调用拆分为类似的内容(一旦您按照lazy1 的建议摆脱了大量的执行人员):

cp_result = self.changeProject(name)
if cp_result is None:
    logging.error('changeProject(%s) is None!', name)
else:
    logging.info('changeProject(%s) is OK (%r)', name, cp_result)
    button.clicked.connect(cp_result)

这样一来,您就可以在错误日志中看到所有导致令人惊讶的返回值的名称,而不是徒劳地尝试“连接到无”,然后可以根据该信息继续调试。但是,通过查看changeProject 的来源,您的错误实际上可能会变得很明显。

编辑connect 的参数当然来自changeProject(不是来自另一个connect!-)——相应地修复了sn-p。

【讨论】:

  • 问题在于列表中的两个项目,都是字符串,没有一个是“无”。使用上面的代码,错误消息在第一行仍然存在。即使将变量名称替换为硬编码的字符串值也会产生相同的问题。 changeProject 函数什么也没做,因为我还没有在代码失败的情况下做到这一点。
  • @Cryptite,列表中的内容(您传递给 changeProject 的参数)是如此的无关紧要以至于可笑:所有重要的是不是 您将什么参数传递给您的 changeProject 方法,但该方法返回的(类型)result。那么,你为什么要提出它呢?!关注connect 返回了什么——显然它返回了None 并且你在changeProject 的代码中有一个可怕的错误(你仍然仔细对我们潜在的帮助者隐藏!)如果您不期望它返回None
  • 对不起,我无意向你们隐藏代码,我犹豫的原因是因为我在您的建议和 Ebral 教授的建议之间尝试了两组不同的代码。和你一起去,我认为混淆是 changeObject 必须返回一些东西,因为它没有。现在从它返回一个字符串值会产生错误“TypeError:connect() 插槽参数应该是可调用的或信号,而不是 'str'”。我已经用当前代码编辑了 OP。
【解决方案3】:

我认为你运行 'exec' 太多了,IMO。您的问题是您正在尝试连接到 QPushButton 的 .clicked(),这确实是一个信号。你真的需要在这里传递参数吗

exec 'self.btn_%s.clicked.connect(self.changeProject("%s"))' % (x, x)

因为如果你不这样做,你可以像这样连接它:

self.connect(self.btn_%s, SIGNAL('clicked()'), self.changeProject)

如果您需要知道点击了哪个按钮,您可以遍历列表以查找点击了哪个按钮:

for x in buttons:
if x.isDown(): (function)


你也可以使用 pyqtSignal。

【讨论】:

  • 这有助于将单击的按钮连接到 changeProject,但是当遍历按钮以找出谁“isDown”时,它们都被评估为被按下。
  • 你能展示一下代码吗?我的按钮为 False。 (我是新人,发现按 可以保存编辑,如果这会导致任何问题.. 抱歉)我想编辑它以添加您也可以将按钮列表转换为本地对象,即。自我按钮。如果所有按钮都将是本地的,您可以将列表设为本地并重新使用它。
【解决方案4】:

感谢您的帮助。我偶然发现了 QSignalMapper,结果证明这正是我所需要的。

http://pysnippet.blogspot.com/2010/06/qsignalmapper-at-your-service.html

【讨论】:

    【解决方案5】:

    QSignalMapper 是使用 Qt 完成此任务的公认方法,但我发现使用 PyQt 它有点麻烦,因为有一些更简单的选项可用。最简单的方法可能是 1) 用唯一的 id 标记每个按钮,以便您可以将它们区分开来(或者只使用按钮的文本),然后 2) 使用 QObject.sender() 来确定哪个按钮发出了信号。例如:

    for x in self.buttons:
        name = str(x)
        button = QtGui.QPushButton(Frame)
        button.setText(name)
        button.uniqueId = name  ## make this whatever you want..
        button.clicked.connect(buttonClicked)
    
    def buttonClicked():
        button = QObject.sender()
        uid = button.uniqueId  ## got your ID back
    

    【讨论】:

      【解决方案6】:

      我想解决这个问题,并提到我刚刚用来解决这个策略的另一个策略/hack。这是一个有些具体的策略,并不总是有效,但我选择为这种设置的更新实现做的是将按钮设置为可检查。

      这最终成为阻力最小的路径,因为我随后能够遍历布局并简单地检查 .isChecked() 中哪个按钮为真。不需要 SignalMapping 或额外的属性。

      【讨论】:

        猜你喜欢
        • 2016-05-16
        • 1970-01-01
        • 2012-06-22
        • 2017-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-13
        • 2021-12-17
        相关资源
        最近更新 更多