【问题标题】:Python: How do I prevent delayed expansion in the QTimer.singleShot(..) function? [duplicate]Python:如何防止 QTimer.singleShot(..) 函数中的延迟扩展? [复制]
【发布时间】:2016-09-13 15:37:51
【问题描述】:

我经常使用QTimer.singleShot(..) 函数来执行某个动作/函数,但会有一些延迟。当然,我也可以使用 time.sleep(..) 来做到这一点,但这会冻结我的用户界面。

有时您想将参数传递给延迟函数。这就是 Python 的 lambda 功能派上用场的地方。看看下面的例子:

    #######################################
    #   Print 'Hello world' vertically    #
    #######################################
    myString = 'Hello world'
    i = 0
    for c in myString:
        QtCore.QTimer.singleShot(10 + i*100, lambda: print(str(c)))
        i += 1

人们会直观地期望左侧显示的输出。但是你实际上得到了一个字符 'd' 的垂直列表——它是给定字符串中的最后一个字符(令人惊讶)。

         _                                _
    H     |                          d     |
    e     |                          d     |
    l     |                          d     |
    l     |                          d     |
    o     |   Result you             d     |   Result you
           >  would expect           d      >  actually get!
    w     |                          d     |
    o     |                          d     |
    r     |                          d     |
    l     |                          d     |
    d     |                          d     |
         _|                               _|

似乎QTimer.singleshot(..) 函数应用了“延迟扩展”原则。在某些情况下这很好,但并非总是如此。

你如何控制扩展?可以强制立即扩容吗?


示例代码:

将以下代码复制粘贴到一个新的 python 文件中,然后从 shell 运行它。

    import sys
    from PyQt4 import QtGui, QtCore

    class MainForm(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MainForm, self).__init__(parent)

            # create button
            self.button = QtGui.QPushButton("QTimer.singleShot(..)", self)
            self.button.clicked.connect(self.btnAction)
            self.button.resize(200, 30)


        def btnAction(self):
            myString = 'Hello world'
            i = 0
            for c in myString:
                QtCore.QTimer.singleShot(10 + i*100, lambda: print(str(c)))
                i += 1


    def main():
        app = QtGui.QApplication(sys.argv)
        form = MainForm()
        form.show()
        app.exec_()

    if __name__ == '__main__':
        main()

单击按钮时,您将在 shell 中看到“Hello world”示例:

【问题讨论】:

    标签: python qt python-3.x pyqt pyqt5


    【解决方案1】:

    我想我找到了答案。 functools.partial(..) 库允许您执行与 lambda:.. 功能完全相同的操作,只是参数被冻结:-)

    import sys
    from PyQt4 import QtGui, QtCore
    import functools
    
    
    
    class MainForm(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MainForm, self).__init__(parent)
    
            # create button
            self.button = QtGui.QPushButton("QTimer.singleShot(..)", self)
            self.button.clicked.connect(self.btnAction)
            self.button.resize(200, 30)
    
    
        def btnAction(self):
            myString = 'Hello world'
            i = 0
            for c in myString:
                #QtCore.QTimer.singleShot(10 + i*100, lambda: print(str(c)))
                QtCore.QTimer.singleShot(10 + i * 100, functools.partial(print, str(c)))
                i += 1
    
    
    def main():
        app = QtGui.QApplication(sys.argv)
        form = MainForm()
        form.show()
        app.exec_()
    
    if __name__ == '__main__':
        main()
    

    编辑:

    感谢@ekhumoro 的评论。您的代码行也可以:

    QtCore.QTimer.singleShot(10 + i*100, lambda arg=c: print(str(arg)))
    

    【讨论】:

    • lambda arg=c: print(str(arg)).
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 2019-03-05
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多