0

我对 Python 的 PyQT4 有疑问。有一个带有文本和按钮的标签连接到功能。该函数可以先改变标签的文本,然后调用其他函数。它有一个问题:函数首先执行,然后更改标签的文本。

代码:

# -*- coding: utf-8 -*-
import time
import sys
from PyQt4 import QtCore, QtGui

def timesleep():
    print("start sleep")
    time.sleep(5)
    print("stop sleep")



class AnyWidget(QtGui.QWidget):
    def __init__(self,*args):

        QtGui.QWidget.__init__(self,*args)
        self.setWindowTitle("PETHARD")
        boxlay = QtGui.QHBoxLayout(self)
        frame = QtGui.QFrame(self) # Фрейм
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setFrameShadow(QtGui.QFrame.Raised)

        gridlay = QtGui.QGridLayout(frame) # Менеджер размещения элементов во фрейме
        label = QtGui.QLabel(u"Welcome",frame) # Текстовая метка.
        global glabel
        glabel = label
        gridlay.addWidget(label,0,0)
        button1 = QtGui.QPushButton(u"Load From MC", frame)
        self.connect(button1, QtCore.SIGNAL("clicked()"), self.ts)
        gridlay.addWidget(button1,1,0)
        boxlay.addWidget(frame)

    def ts(self):
        global glabel
        glabel.setText(u"Waiting...")
        timesleep()

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    aw = AnyWidget()
    aw.show()
    sys.exit(app.exec_())

请帮我解决这个问题。

4

3 回答 3

2

它的工作原理是这样的,因为渲染是稍后在 app.xml 中完成的。因此,您glabel.text会立即更改,但在函数调用后您会在屏幕上看到更改的文本ts,因为绘图是在循环结束时完成的。

如果您真的想在新框架中调用您的函数(在渲染新文本之后),请使用计时器:

timer = QtCore.QTimer()
QtCore.QObject.connect(
    timer,
    QtCore.SIGNAL("timeout()"),
    self.ts
)
timer.start(10)

它应该在十毫秒后调用你的函数,所以实际上可能是在渲染之后。

于 2013-02-08T12:10:54.993 回答
1

您永远不想将您的 GUI 与长期运行的功能捆绑在一起。标签不更新只是问题的一种表现。即使你在调用函数之前更新了标签,它仍然会“冻结”你的 GUI——在长时间运行的函数完成之前,没有小部件会响应用户。

如果您必须运行这样的函数,请查看是否有办法将其分解为小块,每个小块都将控制权交给 GUI,或者考虑使用单独的线程来运行该函数:

import time
import sys
from PyQt4 import QtCore, QtGui


class TimeSleep(QtCore.QThread):
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.parent = parent

    def run(self):
        print("start sleep")
        time.sleep(5)
        print("stop sleep")
        self.parent.glabel.setText(u"Done")


class AnyWidget(QtGui.QWidget):
    def __init__(self, *args):

        QtGui.QWidget.__init__(self, *args)
        self.setWindowTitle("PETHARD")
        boxlay = QtGui.QHBoxLayout(self)
        frame = QtGui.QFrame(self)  # Фрейм
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setFrameShadow(QtGui.QFrame.Raised)

        gridlay = QtGui.QGridLayout(
            frame)  # Менеджер размещения элементов во фрейме
        label = QtGui.QLabel(u"Welcome", frame)  # Текстовая метка.
        self.glabel = label
        gridlay.addWidget(label, 0, 0)
        button1 = QtGui.QPushButton(u"Load From MC", frame)
        self.connect(button1, QtCore.SIGNAL("clicked()"), self.ts)
        gridlay.addWidget(button1, 1, 0)
        boxlay.addWidget(frame)

    def ts(self):
        self.glabel.setText(u"Waiting...")
        self.thread = TimeSleep(parent=self)
        self.thread.start()


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    aw = AnyWidget()
    aw.show()
    sys.exit(app.exec_())

这是一个关于如何处理长时间运行的函数的wiki 页面。

于 2013-02-08T12:29:55.260 回答
1

标签的文本正在更改,但是因为您阻塞了主线程,所以您没有给 Qt 绘制它的机会。

使用QCoreApplication::processEventsQCoreApplication::flush

def ts(self):
    glabel.setText(u"Waiting...")
    QtCore.QCoreApplication.processEvents()
    QtCore.QCoreApplication.flush()
    timesleep()
于 2013-02-08T12:48:05.787 回答