1

我想将调用信号的对象作为参数传递给函数,以便我可以在该函数中使用该对象进行操作。该对象是 QLineEdit 小部件。这是示例:

self.fieldList = []

for i in range(10):
        self.valueField = QtGui.QLineEdit()
        self.fieldList.append(self.valueField)
        self.fieldList[i].cursorPositionChanged.connect(lambda: (self.checkState(self.fieldList[i], palette1, palette2)))

def checkState(self, line, palette1, palette2):
        if len(line.text()) > 3:
            line.setPalette(palette1)
        else:
            line.setPalette(palette2)

因此,如您所见,我试图将列表元素self.fieldList[i]作为参数传递给checkState()函数中的名称行。如果我在checkState()函数中明确定义fieldList元素(即self.fieldList[0] ) ,则代码可以完美运行,但我不能将其作为参数传递。我究竟做错了什么?

顺便提一句。当我尝试运行程序时,编译器没有给我错误消息,但它根本不会做它应该做的工作(当我写超过 3 个字符时改变 QLineEdit 的颜色)

编辑:

@dex19dt

是的,这是一个例子,但你是对的!只有最后一个 QLineEdit 可以正常工作!

问题是,我不能给所有这些小部件命名,因为它们的数量取决于所选的层,这意味着有时有 5 个小部件,有时甚至是 11 或 75 个。

我可以轻松地命名这些小部件并设置文本,如下所示:

 self.fieldList[i].setObjectName(_fromUtf8("attributeValueField_{0}".format(i)))
 self.fieldList[i].setText(_fromUtf8("{0}".format(value.toString())))

这适用于每个小部件,但我不知道如何定义信号?你有想法吗?


编辑:

@dex19dt

好的,所以我问了这个索引没有“坚持”到函数调用的问题,我发现这正是 python 的工作方式,为了解决这个问题,我需要替换这一行:

self.fieldList[i].cursorPositionChanged.connect(lambda: (self.checkState(self.fieldList[i], palette1, palette2)))

有了这个:

self.fieldList[i].cursorPositionChanged.connect(lambda old, new, i=i: (self.checkState(self.fieldList[i], palette1, palette2)))

所以这种方式当前索引复制到信号索引。虽然我不太确定为什么会有old, new一部分。它是指 lambda 函数还是简单地将左定义i为旧变量,右定义i为新变量...尝试谷歌搜索,但没有成功。

4

1 回答 1

1

好吧,我假设您问题中的代码是一个示例,而不是您的真实代码。因为,由于您在没有附加参数的循环中创建小部件,结果将是窗口中所有对象的重叠。你看,所有的 lineEdits 都在同一个地方(默认情况下,窗口的左上角)。如果是这样的话,真的很难说问题出在哪里,因为在我看来,这只是知道 lineEdit 的哪个实例正在发送信号的问题。

所以我会告诉你如何使上面的代码工作,如果不是这样,你可以随时回复。

这完全取决于信号的连接方式。如果您查看您的代码,您将创建具有相同名称 (self.valueField) 的所有 lineEdits。对象都被创建并且它们在内存中有自己的位置,但是它们在连接中的引用总是被最后一个连接覆盖。你甚至可以进行测试。如果将此行添加到 checkState 函数:

print self.fieldList.index(line)

您会看到信号总是为列表的最后一项调用,这也是最后一个连接的信号。

您可以简单地使用不同的名称一一设置所有 lineEdits。并创建您的列表,同时在其中输入所有名称。这样,您的 for 循环将仅连接 lineEdits 而不再创建它们。

编辑:

好的。完成这项工作的一种方法是使用 SignalMapper。看看这里的文档

在上面的示例中,您可以执行以下操作:

首先声明映射器,与声明其他小部件的方式相同:

self.myMapper = QtCore.QSignalMapper()

在你的第一个 for 循环之后。您遍历列表:

for item in self.fieldList:
     self.myMapper.setMapping(item, self.fieldList.index(item))
     item.textEdited.connect(self.myMapper.map)
self.myMapper.mapped[int].connect(checkState)

所以这将做的是它将列表中的每个对象与其在列表中的相应索引(int)映射。因此,当发出信号时,映射器以该索引值作为参数调用 checkState 函数。这样您就可以再次使用列表到达您的对象:

def checkState(i):
    print (self.fieldList[i].objectName())
    self.fieldList[i].setText("It works!")

如您所见,映射器将仅发送索引作为参数。所以我想你需要用额外的 args 来调整你的函数palette1, palette2。或者您可以使用过滤器之类的初步函数,然后在其中调用正确的 checkState 函数:

def myfilter(i):
    checkState(self.fieldList[i], palette1, palette2)

我很确定存在其他方法来完成这项工作,但是这种方法可以完成这项工作,而没有出现更好的解决方案。

于 2012-06-20T13:05:13.127 回答