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

2024-04-25 22:33:02 发布

您现在位置:Python中文网/ 问答频道 /正文

应用程序应该显示像素网格中的图像。所有像素的颜色应每秒更改30次。启动应用程序几秒钟后,像素更新将停止。当窗口调整大小时,像素更新继续。随着像素网络的长期更新,CPU的消耗大大增加。我在Windows上进行了测试,像素更新几乎立即停止。使用线程库和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

活动监视器屏幕截图

在截图中是菜单栏和工具栏,但是,它们不影响问题

应用程序屏幕截图


Tags: infromimportselfappforifrange
1条回答
网友
1楼 · 发布于 2024-04-25 22:33:02

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_())

相关问题 更多 >