如何更改 QPalette 的当前颜色组
Posted
技术标签:
【中文标题】如何更改 QPalette 的当前颜色组【英文标题】:How to change current color group for QPalette 【发布时间】:2017-01-11 17:57:21 【问题描述】:我正在尝试更改 QPalette 的当前颜色组,但似乎 QPalette 的 setCurrentColorGroup 方法根本不起作用。
我正在运行这段代码:
app = QtGui.QApplication(sys.argv)
button = QPushButton()
svgWidget = QSvgWidget(resources_paths.getPathToIconFile("_playableLabels/42-labelPlay-disabled-c.svg"))
button.setLayout(QHBoxLayout())
button.layout().addWidget(svgWidget)
button.setFixedSize(QSize(300, 300))
print button.palette().currentColorGroup()
button.setEnabled(False)
print button.palette().currentColorGroup()
button.palette().setCurrentColorGroup(QPalette.ColorGroup.Normal)
print button.palette().currentColorGroup()
button.show()
print button.palette().currentColorGroup()
app.exec_()
这是我得到的输出:
PySide.QtGui.QPalette.ColorGroup.Normal
PySide.QtGui.QPalette.ColorGroup.Disabled
PySide.QtGui.QPalette.ColorGroup.Disabled
PySide.QtGui.QPalette.ColorGroup.Disabled
Process finished with exit code -1
所以... setCurrentColorGroup 似乎什么都不做。关于如何更改当前颜色组的任何想法?
提前致谢!
(顺便说一句,我在 Windows 7 系统上运行 PySide 1.2.4 和 Qt 4.8)
【问题讨论】:
palette()
方法是 const &
- 即在 python 术语中,它返回一个副本,而不是引用。所以您需要修改返回的调色板,然后使用button.setPalette(palette)
应用更改。但是,使用setCurrentColorGroup
仍然不太可能产生任何效果,因为该按钮仍将被禁用。此外,您需要注意某些样式不会使用调色板进行所有类型的绘图(这主要影响某些版本的 Windows 和 OSX)。也许你应该解释一下你试图通过这种方式使用调色板来实现什么。
@ekhumoro 我有一个按钮(QPushButton 的扁平无边框子类),它使用 svg 作为图标。源 svg 具有红色背景,当我禁用按钮时变为灰色。我不希望图标颜色失真。我不确切知道按钮在禁用时如何改变颜色,但我发现它应该与调色板有关,所以我尝试将调色板的 currentColorGroup 设置回 Normal(而不是 Disabled),但确实如此没什么……
@ekhumoro 我正在使用 PySide,所以我没有 const 变量或指针之类的东西。我验证了每次调用 button.palette() 时都会得到相同的 QPalette 实例,但这可能只是一个包装器?我会按照您的建议使用 setPalette() 尝试一下。
@ekhumoro 它也不起作用......事实上,创建一个 QPalette 然后在它上面使用 setCurrentColorGroup 也没有任何作用。我觉得这真的很奇怪:/
不,您通过 Python 使用 Qt,因此 C++ 签名始终是相关的。如果你不理解这个关键点,你将永远无法有效地使用 PySide/PyQt。在 Python 中,修改可变对象(例如列表)的副本,不会修改原始对象 - 在这方面 C++ 没有什么不同。因此,如果一个 Qt 方法返回一个const&
,那么,在 PySide 中,你会得到一个副本;但如果它返回一个指针,你会得到原来的。 PySide 只是 C++ 库的一个薄包装器。在 Qt 中调用 PySide 方法总是调用完全相同的方法。
【参考方案1】:
您似乎正在尝试更改图标的呈现方式,而不是小部件的绘制方式,因此调色板不是要使用的正确 API。相反,您应该使用QIcon,它允许将不同的图像用于各种modes 和states。
要对Normal
和Disabled
模式使用相同的图像,您可以使用如下代码:
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap('image.svg'), QtGui.QIcon.Normal)
icon.addPixmap(QtGui.QPixmap('image.svg'), QtGui.QIcon.Disabled)
button = QtGui.QPushButton()
button.setIcon(icon)
但是,您应该仔细注意 Qt 文档中的这个警告:
自定义图标引擎可以随意忽略额外添加的像素图。
因此不能保证这适用于所有平台上的所有小部件样式。
更新:
如果上述方法不起作用,则可能意味着小部件样式正在控制禁用图标的呈现方式。相关的QStyle
API 是generatedIconPixmap,它返回根据icon mode 和样式选项修改的像素图的副本。似乎这种方法可能有时也会考虑调色板(与我上面所说的有些相反)-但是当我对此进行测试时,它没有任何影响。我像这样重置调色板:
palette = self.button.palette()
palette.setCurrentColorGroup(QtGui.QPalette.Normal)
palette.setColorGroup(QtGui.QPalette.Disabled,
palette.windowText(), palette.button(),
palette.light(), palette.dark(), palette.mid(),
palette.text(), palette.brightText(),
palette.base(), palette.window(),
)
button.setPalette(palette)
当按钮被禁用时颜色看起来很正常 - 但图标仍然是灰色的。不过,您可能想尝试一下,以防在您的平台上出现不同的情况(如果没有,请不要感到惊讶)。
似乎控制图标禁用的正确方法是创建一个QProxyStyle
并覆盖generatedIconPixmap
方法。不幸的是,这个类在 PyQt4 中不可用,但我在 PyQt5 中测试过它,它可以工作。所以我目前唯一可行的解决方案是升级到 PyQt5,并使用QProxyStyle
。这是一个演示脚本,展示了如何实现它:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class ProxyStyle(QtWidgets.QProxyStyle):
def generatedIconPixmap(self, mode, pixmap, option):
if mode == QtGui.QIcon.Disabled:
mode = QtGui.QIcon.Normal
return super(ProxyStyle, self).generatedIconPixmap(
mode, pixmap, option)
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.button = QtWidgets.QPushButton(self)
self.button.setIcon(QtGui.QIcon('image.svg'))
self.button2 = QtWidgets.QPushButton('Test', self)
self.button2.setCheckable(True)
self.button2.clicked.connect(self.button.setDisabled)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
layout.addWidget(self.button2)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle(ProxyStyle())
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
【讨论】:
您好!我就是这样使用 QIcon:cls.PlayEnabledIcon = QIcon(resources_paths.getPathToIconFile("_playableLabels/42-labelPlay-enabled.svg")) cls.PlayEnabledIcon.addFile(resources_paths.getPathToIconFile("_playableLabels/42-labelPlay-disabled-c.svg"), mode=QIcon.Disabled)
我的红色图标仍然呈现灰色。
@GuillermoAres。正如我所说:“不能保证这将适用于所有平台上的所有小部件样式”。我在我的答案中添加了更多信息,表明可能的解决方法。
我读到了,但我知道它并没有忽略我为QIcon.Disabled
模式添加的文件,因为它与我为@987654337 设置的文件完全不同@(第一个是“播放”三角形,另一个是感叹号)。它在禁用时确实显示感叹号,但它会将问号的颜色从红色变为灰色。我已经看到 Qt 自动更改禁用按钮的图标颜色,这就是为什么我认为它可能与调色板有关,但可能是引擎本身。对我来说太模糊了。谢谢你的耐心! :)
顺便说一句,我真的不知道该怎么处理这个问题。有点乱了既然你在这些事情上似乎比我更有经验……我应该把你的答案标记为正确吗?以上是关于如何更改 QPalette 的当前颜色组的主要内容,如果未能解决你的问题,请参考以下文章
QT动态改变控件背景颜色:用QPalette得到一个颜色m_penColor,如何让一个pushb