【问题标题】:how can i real time update the text without affecting other event(pyqt)如何在不影响其他事件的情况下实时更新文本(pyqt)
【发布时间】:2016-06-19 22:21:36
【问题描述】:

在我的程序中,我想不断地将文本设置到文本浏览器中,但是当我单击另一个按钮时它似乎有延迟。有我的代码:

class Ui_MainWindow(QWidget):
  def __init__(self):
    QWidget.__init__(self)
    self.setupUi(self)
    self.th0 = TestThread()
    self.pushButton.clicked.connect(self.runthread)

  def runthread(self):
    self.th0.start()
    self.chilWid.Consumer()
    QtGui.qApp.processEvents()

  def setupUi(self, Widget):             
    self.gridLayout = QtGui.QGridLayout()
    self.pushButton = QtGui.QPushButton()
    self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
    self.chilWid = ChildWid()
    self.gridLayout.addWidget(self.chilWid, 1, 0, 1, 1)

    self.setLayout(self.gridLayout)

manager = Manager()
manager2 = Manager()
q = manager.Queue()
q2 =manager2.Queue()
l = manager.Lock()
l2 =manager2.Lock()

这个类是一个控制生产者的线程

class TestThread(QThread):
 def __init__(self):
    QThread.__init__(self)
    self.t = ChildWid()
 def run(self):
    while (not self.stopped):
        ps0 = Process(target=Producer, args=(q, l, 'eth0', q2, l2))        
        #### Producer is another program that will generate 
             text continually and save into q
        ps0.start()    

这个类只包含一个文本浏览器,将由 MainWindow 类插入。它还从队列中收集数据并将其显示在文本浏览器上

class ChildWid(QWidget):
 def __init__(self):
    QWidget.__init__(self)
    self.text = QTextEdit()
    self.lay = QHBoxLayout(self)
    self.lay.addWidget(self.text)

 def Consumer(self):
    global q, q2, q3,l,l2,l3
    while True:
        try:
            task = q.get(block=False)
            QtGui.qApp.processEvents()
            self.text.setText(str(task))
        except:
            pass

当我点击pushButton时,文本浏览器会正常显示Producer生成的文本。但是像pushbutton 这样的另一个按钮或整个用户界面响应非常慢。对我有什么建议吗?谢谢

**********新更新

class TestThread(QThread,QObject):
testsinal = pyqtSignal(str)

def __init__(self):
     . . .
    self.t = ChildWid()

def TestSignal(self):
    self.testsinal.emit('some text message')
    self.testsinal.connect(self.handle)
@QtCore.pyqtSlot(str)
def handle(self,str):
    print str
    self.t.text.setText(str)

def run(self):
    print"Thread run normally"
    while (self.stopped):
        ps0 = Process(target=L2PS_v1a4.main, args=(q, l, 'eth0', q2, l2, q3))
        ps0.start()

        self.TestSignal()

【问题讨论】:

  • self.text.setText(str(task))之后尝试self.text.update()
  • 不行,问题依旧存在:(
  • 我弄错了,您需要立即致电self.text.repaint()进行重绘
  • 谢谢,使用'repaint()' 后文字可以持续显示,但整个用户界面响应仍然很慢。我不能点击另一个按钮
  • 按钮好像有响应,但是GUI响应很慢。这意味着当我单击按钮时,会显示按钮的效果,但 GUI 会在片刻后显示具有单击状态的按钮

标签: python multithreading qt pyqt


【解决方案1】:

带有阻塞while 循环的Consumer 方法看起来非常讨厌。它试图表现得像某种假的事件循环,但它无法像真实的东西一样有效地运行。摆脱它。

执行此操作的正确方法是在TestThread 类上定义一个自定义信号,然后使用它从run() 方法中发出文本消息。跨线程信号是线程安全的,并被发布到接收线程的事件队列中。这意味着它们是异步处理的,因此不会阻塞 GUI:

class TestThread(QThread):
    testSignal = QtCore.pyqtSignal(str)
    ...

    def run(self):
        while (not self.stopped):
            ps0 = Process(target=Producer, args=(q, l, 'eth0', q2, l2))        
            ps0.start()
            self.testSignal.emit('some text message')


class ChildWid(QWidget):
    ...

    QtCore.pyqtSlot(str)
    def handleTestSignal(self, message):
        print(message)
        self.text.setText(message)


class Ui_MainWindow(QWidget):
    def __init__(self):
        ...
        self.th0.testSignal.connect(self.chilWid.handleTestSignal)

【讨论】:

  • 感谢您的建议。但是如何从 run() 发出文本消息? pyqt 文档说 emit 函数是用来发出信号的?
  • @RforMaser。嗯,是的 - 完全正确。请参阅我的更新答案。您只需要将一个插槽连接到messageSent 信号。
  • 但我的插槽无法执行self.t.text.setText(str)。 slot 方法可以执行print str。查看我更新的代码
  • @RforMaser。您更新的代码是错误的。工作线程和 GUI 必须完全分开。该线程只是在后台执行非 GUI 工作,并在它有新结果时发出信号。 GUI 异步接收这些信号,并相应地更新其小部件。所有 GUI 操作必须发生在主线程中。请参阅我更新的答案,了解代码的结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
相关资源
最近更新 更多