python-2.7 - 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 正在运行。
解决方案
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_())