1

我正在尝试遍历 PySide2 应用程序中的列表。因此,每次按下“下一步”按钮时,都会从列表中返回并显示下一项。我可以跟踪列表中最近读取的条目的索引,并在每个插槽调用时手动增加索引,但我认为将插槽转换为生成器函数可能更优雅。但它不起作用。

最小(非)工作示例如下。

import sys
from PySide2.QtWidgets import QApplication, QPushButton
from PySide2.QtCore import SIGNAL, QObject

def func():
    stringEntries=["One", "Two", "Three"]
    for item in stringEntries:
        # In the application this sets the values of a numpy array 
        # and fires a signal which updates a matplotlib canvas but meh, whatever
        print("func ", item, " has been called!")
        # This sort of works without the following yield statement
        yield

app = QApplication(sys.argv)
button = QPushButton("Next")
QObject.connect(button, SIGNAL ('clicked()'), func)
button.show()                                                                                             

sys.exit(app.exec_())

我有点期待每次按下“下一步”按钮时都会打印一个不同的字符串,但它只是坐在那里嘲笑我......

有人能指出我从根本上误解的事情吗?

4

1 回答 1

1

正如@jasonharper在评论中指出的那样,每次按下生成问题的按钮时,您都会创建一个新的迭代器,一个可能的解决方案是创建一个具有迭代器作为属性的类,并使用 __call__ 方法查看它,为了使其简单优雅,我创建了一个装饰器:

from PySide2.QtCore import QObject
from PySide2.QtWidgets import QApplication, QPushButton


class decorator:
    def __init__(self, f):
        self._f = f
        self._iterator = None

    def __call__(self, *args, **kwargs):
        if self._iterator is None:
            self._iterator = self._f(*args, **kwargs)
        try:
            return next(self._iterator)
        except StopIteration:
            pass


@decorator
def func():
    stringEntries = ["One", "Two", "Three"]
    for item in stringEntries:
        print("func ", item, " has been called!")
        yield


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    button = QPushButton("Next")
    button.clicked.connect(func)
    button.show()

    sys.exit(app.exec_())
于 2019-09-03T16:48:47.607 回答