PySide/PyQt:在GUI加载后执行函数

3
我正在开发一个在会话启动时进行文件操作的小工具。为了确保用户能够获得可视化反馈,我希望将其与进度条相关联。
目前为止,我的进展如下:
import sys
import time
from PySide.QtGui import *


class ProgressWindowWidget(QWidget):
    def __init__(self, parent=None):
        super(ProgressWindowWidget, self).__init__()

        self.init_ui()

    def init_ui(self):
        self.setGeometry(500, 500, 600, 100)
        self.setWindowTitle('Progress')

        self.layout_ = QGridLayout()
        self.setLayout(self.layout_)

        self.progress_bar = QProgressBar()
        self.layout_.addWidget(self.progress_bar, 0, 0, 1, 1)

    def my_operations(self):
        print('do something 1')
        time.sleep(2)
        print('do something 2')
        time.sleep(2)
        print('do something 3')
        time.sleep(2)


def main():
    app = QApplication(sys.argv)
    progress_window = ProgressWindowWidget()
    progress_window.show()
    progress_window.my_operations()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

我的问题是my_operations先执行,然后我的GUI才加载。我希望只有在进度条加载完成后才执行my_operations,这样我才能更新它。
根据这里的内容,这与exec_ main循环有关,但显然我不理解这里的某些东西,因为我在show之后调用了my_operations
不用说,我是一个初学者。有人有想法吗? 谢谢。

你能在show和你的函数之间加一个sleep吗?这样可以看看是否有任何效果。 - SuperStew
我已经这样做了,GUI 无论如何肯定在等待。 - Munshine
1个回答

2
每个图形用户界面都存在一个事件循环,允许您处理用户、操作系统等的事件,例如鼠标、键盘等。因此,如果您阻止此处理,GUI 将无法更新其状态,您的情况是由于 time.sleep() 引起的,它是阻塞的,防止 GUI 激活显示窗口的状态。因此,作为基本规则:不要在 GUI 的主线程中使用 time.sleep(),我想 time.sleep() 模拟需要一定时间的任务,对于这种情况,您必须从另一个线程执行此任务,如果您想更新 GUI,则必须通过信号进行,不应直接进行。

在以下示例中,我将使用 threading.Thread() 创建一个新线程和一个信号来更新 GUI:

import sys
import time
import threading
from PySide import QtCore, QtGui


class ProgressWindowWidget(QtGui.QWidget):
    progressSignal = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(ProgressWindowWidget, self).__init__()
        self.init_ui()

    def init_ui(self):
        self.setGeometry(500, 500, 600, 100)
        self.setWindowTitle('Progress')

        self.layout_ = QtGui.QGridLayout()
        self.setLayout(self.layout_)

        self.progress_bar = QtGui.QProgressBar()
        self.progressSignal.connect(self.progress_bar.setValue)
        self.layout_.addWidget(self.progress_bar, 0, 0, 1, 1)

    def my_operations(self):
        print('do something 1')
        time.sleep(2)
        self.progressSignal.emit(33)
        print('do something 2')
        time.sleep(2)
        self.progressSignal.emit(66)
        print('do something 3')
        time.sleep(2)
        self.progressSignal.emit(100)


def main():
    app = QtGui.QApplication(sys.argv)
    progress_window = ProgressWindowWidget()
    progress_window.show()
    t = threading.Thread(target=progress_window.my_operations)
    t.start()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

谢谢!但是我加了 time.sleep 为了模拟我实际尝试执行的操作(如复制文件),但问题仍然存在。我想要实现的是在加载UI后,触发一个事件来执行 my_operations。但我会研究你的解决方案 :) - Munshine
@Munshine 如果你检查了我的解决方案,请指出来,这样我的解决方案就可以与time.sleep()或像复制文件这样的重任务一起工作。如果我的答案对你有帮助,请不要忘记将其标记为正确的答案,如果你不知道如何操作,请查看[tour],那是最好的感谢方式。 :-) - eyllanesc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接