You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide6窗口显示前后修改Label颜色的性能差异原因探究

问题:Qt样式表与QPalette修改Label背景色的性能差异

我正在构建一个Label网格,可根据网格位置的数值持续修改其背景色。采用三种方式定位指定网格的Label并修改颜色:changeBox1和changeBox2使用样式表(style sheet),changeBox3直接修改QPalette。

测试发现,在类的__init__函数中调用这些方法时,运行速度远快于窗口调用show()之后。其中直接修改QPalette的changeBox3方法性能始终稳定,而使用样式表的方法性能差异显著。疑惑这是否与Qt(或PySide)在部件实例化后处理样式表的方式有关?

使用Python 3.10.15,以下是500次运行的平均耗时数据:

Average execution time of changeBox1 in init over 500 runs: 1.0947501286864281e-06 seconds
Average execution time of changeBox2 in init over 500 runs: 4.599159583449364e-07 seconds
Average execution time of changeBox3 in init over 500 runs: 2.514749765396118e-06 seconds
Average execution time of changeBox1 after window.show over 500 runs: 1.4484249986708164e-05 seconds
Average execution time of changeBox2 after window.show over 500 runs: 1.4263415709137917e-05 seconds
Average execution time of changeBox3 after window.show over 500 runs: 2.624250017106533e-06 seconds
Average execution time of myLabel1 over 500 runs: 1.668350026011467e-05 seconds
Average execution time of myLabel2 over 500 runs: 1.4353999868035316e-05 seconds

最小可复现示例(MWE)

import sys
import timeit

from PySide6.QtCore import QSize, Qt
from PySide6.QtGui import QColor, QFont, QPalette
from PySide6.QtWidgets import (
    QApplication,
    QGridLayout,
    QLabel,
    QMainWindow,
    QWidget,
)

arrows = ["↑", "↓", "→", "←"]


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")
        self.setMinimumSize(QSize(400, 300))

        self.layout = QGridLayout()
        self.layout.setSpacing(3)

        xMax = 4
        yMax = 5
        steps = xMax * yMax
        midStep = steps // 2 + 1
        cStep = 255 // midStep
        cRed = 255
        cGreen = 0
        cBlue = 0
        self.labels = {}
        for b in range(steps):
            label = f"T{b}\n{arrows[b % 4]}"
            (x,y) = divmod(b, xMax)
            color = f"{cRed:02x}{cGreen:02x}{cBlue:02x}"
            self.labels[(x, y)] = self.addBox(color, label, x, y)

            if b < midStep:
                cGreen += cStep
            else:
                cRed -= cStep

        widget = QWidget()
        widget.setLayout(self.layout)
        self.setCentralWidget(widget)

        runs = 500
        time1 = timeit.timeit(lambda: self.changeBox1(2, 2), number=runs)
        time2 = timeit.timeit(lambda: self.changeBox2(1, 1), number=runs)
        time3 = timeit.timeit(lambda: self.changeBox3(0, 0), number=runs)

        print(
            f"Average execution time of changeBox1 in init over {runs} runs: {time1 / runs} seconds"
        )
        print(
            f"Average execution time of changeBox2 in init over {runs} runs: {time2 / runs} seconds"
        )
        print(
            f"Average execution time of changeBox3 in init over {runs} runs: {time3 / runs} seconds"
        )

        # Find the fastest way to change the color of a specific widget

    def changeBoxColor(self):
        self.changeBox1(2, 2)
        self.changeBox2(1, 1)
        self.changeBox3(0, 0)

        runs = 500
        time1 = timeit.timeit(lambda: self.changeBox1(2, 2), number=runs)
        time2 = timeit.timeit(lambda: self.changeBox2(1, 1), number=runs)
        time3 = timeit.timeit(lambda: self.changeBox3(0, 0), number=runs)

        print(
            f"Average execution time of changeBox1 after window.show over {runs} runs: {time1 / runs} seconds"
        )
        print(
            f"Average execution time of changeBox2 after window.show over {runs} runs: {time2 / runs} seconds"
        )
        print(
            f"Average execution time of changeBox3 after window.show over {runs} runs: {time3 / runs} seconds"
        )

    def myLabelTimer(self):
        runs = 500
        time1 = timeit.timeit(lambda: self.myLabel1("f0f0f0", "Test"), number=runs)
        time2 = timeit.timeit(lambda: self.myLabel2("f0f0f0", "Test"), number=runs)

        print(
            f"Average execution time of myLabel1 over {runs} runs: {time1 / runs} seconds"
        )
        print(
            f"Average execution time of myLabel2 over {runs} runs: {time2 / runs} seconds"
        )

    def myLabel1(self, color, text):
        tBox = QLabel(text)
        tBox.setAutoFillBackground(True)
        tBox.setAlignment(Qt.AlignCenter)
        tBox.setStyleSheet(f"background: #{color}; font-style: bold; font-size: 24pt")

        return tBox

    def myLabel2(self, color, text):
        tBox = QLabel(text)
        tBox.setAutoFillBackground(True)
        tBox.setAlignment(Qt.AlignCenter)
        palette = tBox.palette()
        palette.setColor(QPalette.Window, QColor(f"#{color}"))
        tBox.setPalette(palette)
        font = QFont()
        font.setPointSize(24)
        font.setWeight(QFont.Bold)
        tBox.setFont(font)

        return tBox

    def addBox(self, color, text, x, y):
        box = self.myLabel2(color, text)
        self.layout.addWidget(box, x, y)

        return box

    def changeBox1(self, x, y):
        cell = self.layout.itemAtPosition(x, y).widget()
        cell.setStyleSheet(
            f"background: #{'0000ff'}; font-style: bold; font-size: 24pt"
        )

    def changeBox2(self, x, y):
        self.labels[(x, y)].setStyleSheet(
            f"background: #{'00f0ff'}; font-style: bold; font-size: 24pt"
        )

    def changeBox3(self, x, y):
        palette = self.labels[(x, y)].palette()
        palette.setColor(QPalette.Window, QColor("#0080ff"))
        self.labels[(x, y)].setPalette(palette)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
window.changeBoxColor()
window.myLabelTimer()
app.exec()

QGraphicsScene/QGraphicsView版本代码

import sys
import timeit

from PySide6.QtCore import QSize, QPoint, Qt
from PySide6.QtGui import QColor, QFont, QPalette
from PySide6.QtWidgets import (
    QApplication,
    QLabel,
    QWidget,
    QGraphicsScene,
    QGraphicsView,
    QHBoxLayout,
)

arrows = ["↑", "↓", "→", "←"]


class Window(QWidget):

    xMax    : int = 4
    yMax    : int = 5
    boxSize : int = 75
    labels  = {}

    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")
        self.setMinimumSize(QSize(self.xMax * self.boxSize, self.yMax * self.boxSize ))

        self.scene = QGraphicsScene(0, 0, self.xMax * self.boxSize, self.yMax * self.boxSize)

        label = self.label("0000ff", "Test",QPoint(self.boxSize,self.boxSize))

        self.scene.addWidget(label)
        self.buildGrid()

        # Define our layout.
        view = QGraphicsView(self.scene)

        hbox = QHBoxLayout(self)
        hbox.addWidget(view)

        self.setLayout(hbox)

    def label(self, color, text, pos : QPoint):
        tBox: QLabel = QLabel(text)
        tBox.setFixedSize(self.boxSize,self.boxSize)
        tBox.setAutoFillBackground(True)
        tBox.setAlignment(Qt.AlignCenter)

        palette = tBox.palette()
        palette.setColor(QPalette.Window, QColor(f"#{color}"))
        tBox.setPalette(palette)

        font = QFont()
        font.setPointSize(24)
        font.setWeight(QFont.Bold)
        tBox.setFont(font)

        tBox.move(pos)

        return tBox

    def buildGrid(self):

        steps = self.xMax * self.yMax
        midStep = steps // 2 + 1
        cStep = 255 // midStep
        cRed = 255
        cGreen = 0
        cBlue = 0
        for b in range(steps):
            label = f"T{b}\n{arrows[b % 4]}"
            (y,x) = divmod(b, self.xMax)
            color = f"{cRed:02x}{cGreen:02x}{cBlue:02x}"
            self.labels[(x, y)] = self.label(color, label, QPoint(x * self.boxSize,y * self.boxSize))
            self.scene.addWidget(self.labels[(x, y)])

            if b < midStep:
                cGreen += cStep
            else:
                cRed -= cStep

    def changeBox(self, x, y):
        palette = self.labels[(x, y)].palette()
        palette.setColor(QPalette.Window, QColor("#0080ff"))
        self.labels[(x, y)].setPalette(palette)

app = QApplication(sys.argv)
window = Window()
window.show()
window.changeBox(0, 0)

runs = 500
time1 = timeit.timeit(lambda: window.changeBox(2, 2), number=runs)
print(
    f"Average execution time of changeBox in init over {runs} runs: {time1 / runs} seconds"
)

app.exec()

内容的提问来源于stack exchange,提问作者JKomp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 19:15:56