首页 > 解决方案 > pyqt marquee 文本在几个小时后挂起

问题描述

我正在使用以下代码使用 pyqt 创建滚动文本。我还在我的 UI 中使用QPainter. 问题是这样的代码可以正常工作,但过了一段时间它就会挂起。消息停止滚动,而其他部分 UI 正在运行。我使用早期堆栈溢出问题中的代码来滚动文本Marquee effect。以下是我的代码的一部分

class MarqueeLabel(QtGui.QLabel):
    def __init__(self, parent=None):
        QtGui.QLabel.__init__(self, parent)
        self.px = 0
        self.py = 15
        self._direction = Qt.RightToLeft #Qt.LeftToRight
        self.setWordWrap(True)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update)
        self.timer.start(20)
        self._speed = 2
        self.textLength = 0
        self.fontPointSize = 0
        self.setAlignment(Qt.AlignVCenter)
        self.setFixedHeight(self.fontMetrics().height())

    def setFont(self, font, size):
        newfont = QtGui.QFont(font, size, QtGui.QFont.Bold)
        QtGui.QLabel.setFont(self, newfont)
        self.setFixedHeight(self.fontMetrics().height())

    def updateCoordinates(self):
        align = self.alignment()
        if align == Qt.AlignTop:
            self.py = 10
        elif align == Qt.AlignBottom:
            self.py = self.height() - 10
        elif align == Qt.AlignVCenter:
            self.py = self.height() / 2
        self.fontPointSize = self.font().pointSize() / 2
        self.textLength = self.fontMetrics().width(self.text())

    def setAlignment(self, alignment):
        self.updateCoordinates()
        QtGui.QLabel.setAlignment(self, alignment)

    def resizeEvent(self, event):
        self.updateCoordinates()
        QtGui.QLabel.resizeEvent(self, event)

    def paintEvent(self, event):
        painter = QPainter(self)
        if self._direction == Qt.RightToLeft:
            self.px -= self.speed()
            if self.px <= -self.textLength:
                self.px = self.width()
        else:
            self.px += self.speed()
            if self.px >= self.width():
                self.px = -self.textLength
        painter.drawText(self.px, self.py + self.fontPointSize, self.text())
        painter.translate(self.px, 0)

    def speed(self):
        return self._speed

    def setSpeed(self, speed):
        self._speed = speed

    def setDirection(self, direction):
        self._direction = direction
        if self._direction == Qt.RightToLeft:
            self.px = self.width() - self.textLength
        else:
            self.px = 0
        self.update()

    def pause(self):
        self.timer.stop()

    def unpause(self):
        self.timer.start()

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        self.signalUpdateUI()
    def signalUpdateUI(self):
        updateUIThread = Thread(target=self.updateUI)
        updateUIThread.daemon = True
        updateUIThread.start()
    def updateUI(self):
        while(1==1):
            #update some text color and contents
            #update marquee label contents
            self.update()
            sleep(2)
    def paintEvent(self, event):
        QWidget.paintEvent(self, event)
        painter = QPainter(self)
        pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)
        painter.setPen(pen)
        painter.drawLine(0,190, 1920,190)
        painter.drawLine(0,300, 1920,300)
        painter.drawLine(0,840, 1920,840)
        painter.drawLine(0,930, 1920,930)

        # Reactangle Box Settings
        painter.setPen(self._rectBoxLine_color)
        painter.setBrush(self._rectBox_color)
        rect = QRect(1430,300,470,535)

        painter.drawRect(rect)
        painter.setFont(QtGui.QFont('Consolas', 60, QtGui.QFont.Bold))
        painter.setPen(QtGui.QColor(0, 0, 0))      
        painter.drawText(QRect(1430,300,470,535), QtCore.Qt.AlignCenter, self._rect_text)

我不知道为什么滚动消息会在几个小时后停止,即使另一部分 UI 正在运行。

标签: python-2.7pyqt4

解决方案


marqueLabel 的实现是高效的,所以我认为这不是错误的原因,另一方面,显示的代码也是不可执行的,但它显示的内容你可以注意到线程在周期性任务中的滥用,在这种情况下图形用户界面禁止直接从另一个线程修改图形用户界面,而且执行的任务不繁重,所以必须使用 QTimer 代替。

from PyQt4 import QtCore, QtGui

class MarqueeLabel(QtGui.QLabel):
    def __init__(self, parent=None):
        super(MarqueeLabel, self).__init__(parent)
        self.px = 0
        self.py = 15
        self._direction = QtCore.Qt.RightToLeft #Qt.LeftToRight
        self.setWordWrap(True)
        self.timer = QtCore.QTimer(self, interval=20)
        self.timer.timeout.connect(self.update)
        self.timer.start()
        self._speed = 2
        self.textLength = 0
        self.fontPointSize = 0
        self.setAlignment(QtCore.Qt.AlignVCenter)
        self.setFixedHeight(self.fontMetrics().height())

    def setFont(self, font, size):
        newfont = QtGui.QFont(font, size, QtGui.QFont.Bold)
        QtGui.QLabel.setFont(self, newfont)
        self.setFixedHeight(self.fontMetrics().height())

    def updateCoordinates(self):
        align = self.alignment()
        if align == QtCore.Qt.AlignTop:
            self.py = 10
        elif align == QtCore.Qt.AlignBottom:
            self.py = self.height() - 10
        elif align == QtCore.Qt.AlignVCenter:
            self.py = self.height() / 2
        self.fontPointSize = self.font().pointSize() / 2
        self.textLength = self.fontMetrics().width(self.text())

    def setAlignment(self, alignment):
        self.updateCoordinates()
        QtGui.QLabel.setAlignment(self, alignment)

    def resizeEvent(self, event):
        self.updateCoordinates()
        QtGui.QLabel.resizeEvent(self, event)

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        if self._direction == QtCore.Qt.RightToLeft:
            self.px -= self.speed()
            if self.px <= -self.textLength:
                self.px = self.width()
        else:
            self.px += self.speed()
            if self.px >= self.width():
                self.px = -self.textLength
        painter.drawText(self.px, self.py + self.fontPointSize, self.text())
        painter.translate(self.px, 0)

    def speed(self):
        return self._speed

    def setSpeed(self, speed):
        self._speed = speed

    def setDirection(self, direction):
        self._direction = direction
        if self._direction == Qt.RightToLeft:
            self.px = self.width() - self.textLength
        else:
            self.px = 0
        self.update()

    def pause(self):
        self.timer.stop()

    def unpause(self):
        self.timer.start()

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self._rectBoxLine_color = QtGui.QColor(QtCore.Qt.green)
        self._rectBox_color = QtGui.QBrush(QtCore.Qt.blue)
        self._rect_text = "_rect_text"

        self.marquee = MarqueeLabel(self)
        self.signalUpdateUI()

    def signalUpdateUI(self):
        timer = QtCore.QTimer(self, interval=2000)
        timer.timeout.connect(self.updateUI)
        timer.start()
        self.updateUI()

    def updateUI(self):
            #update some text color and contents
            #update marquee label contents
            self.marquee.setText(QtCore.QDateTime.currentDateTime().toString())
            self.update()

    def paintEvent(self, event):
        super(MainWindow, self).paintEvent(event)
        painter = QtGui.QPainter(self)
        pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)
        painter.setPen(pen)
        painter.drawLine(0,190, 1920,190)
        painter.drawLine(0,300, 1920,300)
        painter.drawLine(0,840, 1920,840)
        painter.drawLine(0,930, 1920,930)

        # Reactangle Box Settings
        painter.setPen(self._rectBoxLine_color)
        painter.setBrush(self._rectBox_color)
        rect = QtCore.QRect(1430,300,470,535)

        painter.drawRect(rect)
        painter.setFont(QtGui.QFont('Consolas', 60, QtGui.QFont.Bold))
        painter.setPen(QtGui.QColor(0, 0, 0))      
        painter.drawText(QtCore.QRect(1430,300,470,535), QtCore.Qt.AlignCenter, self._rect_text)


if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

推荐阅读