窗口仅在PyQt5中调整大小时更新

时间:2018-12-03 21:23:22

标签: python python-3.x pyqt pyqt5

应用程序应显示来自像素网格的图像。所有像素的颜色应每秒更改30次。启动该应用程序几秒钟后,像素更新将停止。调整窗口大小后,像素更新将恢复。随着像素网络的长期更新,CPU消耗将大大增加。我在Windows上进行了测试,像素更新几乎立即停止。使用Threading库和PyQt5库显示界面。如何在网格中进行稳定的像素更新?

这是我的代码:

from random import choice, randint
from sys import argv
from threading import Thread
from time import sleep

from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import (QApplication, QFrame, QGridLayout, QMainWindow,
                             QMenu, QToolBar, QWidget)


class EmulatorWindow(QMainWindow):
    spacing = None
    app_running = True

    def __init__(self, spacing=1, screen_resolution=(16, 16)):
        super().__init__()
        self.spacing = spacing

        # Pixel Grid
        self.grid = QGridLayout()
        self.grid.setContentsMargins(0, 0, 0, 0)
        self.grid.setSpacing(self.spacing)
        for x in range(0, screen_resolution[0]):
            for y in range(0, screen_resolution[1]):
                pixel = QWidget()
                pixel.setAutoFillBackground(True) 
                self.grid.addWidget(pixel, y, x)

        # Application thread
        self.applicationThread = Thread(target=self.applicationRunner, args=())
        self.applicationThread.start()

        # Window Properties
        self.setGeometry(300, 300, 450, 495)
        self.setWindowTitle('Pixels Grid')

        widget = QWidget()
        widget.setLayout(self.grid)
        self.setCentralWidget(widget)
        self.setMinimumSize(QSize(450, 495))
        self.show()

    def applicationRunner(self):
        color = 0
        while True:
            if self.app_running == False:
                break
            for x in range(0, 16):
                for y in range(0, 16):
                    self.grid.itemAtPosition(x, y).widget().setPalette(QPalette([Qt.red, Qt.blue, Qt.green][color]))
            sleep(1 / 30)
            color = color + 1
            if color == 3:
                color = 0

    def switchSpacing(self):
        self.grid.setSpacing(self.spacing if self.grid.spacing() == 0 else 0)

if __name__ == '__main__':
    app = QApplication(argv)
    ex = EmulatorWindow()
    app.exec_()
    ex.app_running = False

活动监视器屏幕截图

屏幕截图中是MenuBar和ToolBar,但是它们不会影响问题

应用程序截图

1 个答案:

答案 0 :(得分:0)

未使用线程更新GUI的原因是Qt禁止从另一个线程更新图形元素,有关更多信息,请阅读GUI Thread and Worker Thread。如果任务不繁重,则不应该使用线程,例如,如果我们使用以下代码测试何时消耗了更改颜色,则使用线程:

t = QtCore.QElapsedTimer()
t.start()
pal = QtGui.QPalette([QtCore.Qt.red, QtCore.Qt.blue, QtCore.Qt.green][self._color])
for x in range(self.grid.rowCount()):
    for y in range(self.grid.columnCount()):
        w = self.grid.itemAtPosition(x, y).widget()
        if w is not None:
            w.setPalette(pal)
self._color = (self._color +1) % 3
print(t.elapsed(), " milliseconds")

获得以下结果:

4  milliseconds
2  milliseconds
2  milliseconds
3  milliseconds
2  milliseconds
3  milliseconds
3  milliseconds
2  milliseconds
3  milliseconds
# ...

支持我的声明这不是一项繁重的任务,因此在这种情况下,您应该使用QTimer来执行定期任务:

from PyQt5 import QtCore, QtGui, QtWidgets

class EmulatorWindow(QtWidgets.QMainWindow):
    def __init__(self, spacing=1, screen_resolution=(16, 16)):
        super().__init__()
        self.spacing = spacing
        # Pixel Grid
        self.grid = QtWidgets.QGridLayout()
        self.grid.setContentsMargins(0, 0, 0, 0)
        self.grid.setSpacing(self.spacing)
        for x in range(screen_resolution[0]):
            for y in range(screen_resolution[1]):
                pixel = QtWidgets.QWidget(autoFillBackground=True)
                self.grid.addWidget(pixel, y, x)
        # Window Properties
        self.setGeometry(300, 300, 450, 495)
        self.setWindowTitle('Pixels Grid')

        widget = QtWidgets.QWidget()
        self.setCentralWidget(widget)
        widget.setLayout(self.grid)
        self.setMinimumSize(QtCore.QSize(450, 495))
        self._color = 0
        timer = QtCore.QTimer(self, interval=1000/30, timeout=self.applicationRunner)
        timer.start()

    @QtCore.pyqtSlot()
    def applicationRunner(self):
        pal = QtGui.QPalette([QtCore.Qt.red, QtCore.Qt.blue, QtCore.Qt.green][self._color])
        for x in range(self.grid.rowCount()):
            for y in range(self.grid.columnCount()):
                w = self.grid.itemAtPosition(x, y).widget()
                if w is not None:
                    w.setPalette(pal)
        self._color = (self._color +1) % 3

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ex = EmulatorWindow()
    ex.show()
    sys.exit(app.exec_())