如何在不在小部件上重置的情况下在 QIcon 中可视化更改的像素图?

问题描述 投票:0回答:1

现在暗模式终于在 Qt 6.5 中出现在 Windows 中,我注意到我的很多图标在深色背景下看起来不太好。所以我想为明暗模式使用不同的图标。而且,为了让事情变得困难,当用户在他的操作系统上切换模式时,图标会改变(它们的外观)。

为了避免到处都是各种小部件

setIcon()
,我想我会继承
QIcon
并让它在
colorSchemeChanged
信号上改变它的像素图。

class ThemeAwareIcon(QIcon):
    def __init__(self, dark_pixmap, light_pixmap, *args):
        super().__init__(*args)
        self.dark_pm = dark_pixmap
        self.light_pm = light_pixmap
        self.app = QApplication.instance()
        self.app.styleHints().colorSchemeChanged.connect(self.set_appropriate_pixmap)
        self.set_appropriate_pixmap()

    def set_appropriate_pixmap(self):
        current_scheme = self.app.styleHints().colorScheme()
        pm = self.dark_pm if current_scheme == Qt.ColorScheme.Dark else self.light_pm
        self.addPixmap(pm, QIcon.Mode.Normal, QIcon.State.On)

这几乎按预期工作;像素图根据信号改变。只是更改后的像素图没有显示在设置图标的小部件上。我发现使更改可见的唯一方法是重置小部件上的图标,而这正是我首先要避免的。

那么,我的图标类能否以某种方式获救,或者我想要的是不可能通过这种方式实现的?

python pyqt qicon
1个回答
0
投票

经过一番努力,我发现了如何使用

QIconEngine
让图标自己切换。

如果有其他人正在努力理解

QIconEngine
的作用。它只是向图标所在的小部件提供给定大小、模式和状态的像素图。仅此而已。
所以如果你继承它,你只需要确保
pixmap()
返回适当的像素图。

这是一个非常基本的通用实现。任何信号都可以用来触发开关。

如果在 colorscheme 更改时切换,则无需将信号传递给引擎,因为它是全局可用的。

此示例将像素图生成“卸载”到常规

QIcons
。这可能不是最有效的方法,但在所有情况下您都会获得默认行为。

class SwitchingEngine(QIconEngine):
    offload = {}

    def __init__(self, file_name, f1, f2, sig):
        super().__init__()
        self.file_name = file_name
        if self.file_name not in self.offload:
            self.offload[self.file_name] = {
                True: QIcon(f1),
                False: QIcon(f2),
            }
        self.switch = True
        sig.connect(lambda: setattr(self, 'switch', not self.switch))

    def pixmap(self, size: QSize, mode: QIcon.Mode, state: QIcon.State):
        return self.offload[self.file_name][self.switch].pixmap(size, mode, state)


class SwitchingIcon(QIcon):
    def __init__(self, file_name, sig):
        f1 = f'switch1/{file_name}'
        f2 = f'switch2/{file_name}'
        engine = SwitchingEngine(file_name, f1, f2, sig)
        super().__init__(engine)

作为奖励,有一点“带上你自己的图标文件”测试应用程序。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QToolButton, QComboBox, QVBoxLayout, QHBoxLayout, QStyleFactory
from PyQt5.QtGui import QIcon, QIconEngine
from PyQt5.QtCore import QSize

class Window(QWidget):
    def __init__(self):
        super().__init__()
        sw = QPushButton('switch')
        dis = QPushButton('disable')

        but1 = QToolButton()
        but2 = QToolButton()
        but3 = QToolButton()

        icon1 = SwitchingIcon('fn1', sw.clicked)
        icon2 = SwitchingIcon('fn2', sw.clicked)
        icon3 = SwitchingIcon('fn3', sw.clicked)

        but1.setIcon(icon1)
        but2.setIcon(icon2)
        but3.setIcon(icon3)

        sw.clicked.connect(self.update)
        dis.clicked.connect(lambda: but1.setEnabled(not but1.isEnabled()))
        dis.clicked.connect(lambda: but2.setEnabled(not but2.isEnabled()))
        dis.clicked.connect(lambda: but3.setEnabled(not but3.isEnabled()))

        cmb = QComboBox()
        cmb.addItems(QStyleFactory.keys())
        cmb.currentTextChanged.connect(QApplication.instance().setStyle)

        tbs = QHBoxLayout()
        tbs.addWidget(but1)
        tbs.addWidget(but2)
        tbs.addWidget(but3)
        lay = QVBoxLayout(self)
        lay.addWidget(cmb)
        lay.addLayout(tbs)
        lay.addWidget(sw)
        lay.addWidget(dis)

app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())
© www.soinside.com 2019 - 2024. All rights reserved.