2024-06-08 21:21:25 发布
网友
我正在尝试在LinuxMint19(肉桂色)上创建一个pyqt5应用程序。 我有一个“删除”和“应用”按钮,但我想让它们看起来更相关。如图所示:
本机Linux薄荷按钮
更多
这是LinuxMint上带有apply或delete角色的按钮的本机外观,我想在我的应用程序中创建这样的按钮,但我还没有找到这样做的方法
windows和mac似乎有qtmacextras和qtwinextras模块来处理这些东西。Linux有某种qtx11extras,但该模块不提供这种功能
qtmacextras
qtwinextras
qtx11extras
您可以使用样式表根据自己的喜好进行设计
下面是一个独立的示例。当然,您必须使其适应您喜欢的颜色和尺寸。但这应该已经提供了一个起点
import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout GREEN_BUTTON_STYLE = """ QPushButton { border: 4px solid black; border-radius: 4px; color: #ffffff; background-color: #6db442; font-size: 28px; min-height: 40px; min-width: 128px; } QPushButton:pressed { background-color: #646464; } QPushButton:flat { border: none; } """ RED_BUTTON_STYLE = """ QPushButton { border: 4px solid black; border-radius: 4px; color: #ffffff; background-color: #f04a50; font-size: 26px; min-height: 40px; min-width: 128px; } QPushButton:pressed { background-color: #646464; } QPushButton:flat { border: none; } """ class App(QWidget): def __init__(self): super().__init__() self.title = 'button styles' self.init_ui() def init_ui(self): self.setWindowTitle(self.title) self.setGeometry(256, 128, 384, 256) button1 = QPushButton('Launch') button1.setStyleSheet(GREEN_BUTTON_STYLE) button1.setFlat(True) button1.clicked.connect(self.on_click) button2 = QPushButton('Remove') button2.setStyleSheet(RED_BUTTON_STYLE) button2.setFlat(True) button2.clicked.connect(self.on_click) layout = QHBoxLayout() layout.addWidget(button1, alignment=Qt.AlignHCenter) layout.addWidget(button2, alignment=Qt.AlignHCenter) self.setLayout(layout) self.setStyleSheet("background-color:#333333;") self.show() def on_click(self): print('clicked') if __name__ == '__main__': app = QApplication(sys.argv) ex = App() sys.exit(app.exec_())
输出
它看起来是这样的:
虽然已经提供的解决方案可以很好地工作,但并不完全适用于整个应用程序,特别是如果您想要控制对话框按钮的外观
即使将样式表应用于应用程序,也需要确保在父级中正确设置选择器:例如,在另一个答案中,设置没有选择器的背景属性将清除子级的应用程序样式表继承
假设将样式表设置为应用程序,并且仔细编写了所有其他样式表集,那么对话框窗口就会出现问题
如果对话框是手动创建的,则可以通过为每个按钮指定样式表来设置替换颜色,但对于使用静态函数创建的按钮,这是不可能的
在这种情况下,唯一的可能是使用QProxyStyle。下面是一个可能的实现,它还允许设置自定义颜色和字体,并自动为对话框按钮框(取消、忽略等)的“负面”角色设置备用颜色
在本例中,我刚刚将样式应用于应用程序,但消息框是使用information()静态函数创建的。“备用”按钮是使用自定义属性手动设置的:button.setProperty('alternateColor', True)
information()
button.setProperty('alternateColor', True)
class ColorButtonStyle(QtWidgets.QProxyStyle): def __init__(self, *args, **kwargs): if isinstance(kwargs.get('buttonFont'), QtGui.QFont): self._buttonFont = kwargs.pop('buttonFont') else: self._buttonFont = QtWidgets.QApplication.font() self._buttonFont.setPointSize(20) super().__init__(*args, **kwargs) self._buttonFontMetrics = QtGui.QFontMetrics(self._buttonFont) self._defaultButtonColor = QtGui.QColor(109, 180, 66) self._defaultTextColor = QtGui.QColor(QtCore.Qt.white) self._alternateButtonColor = QtGui.QColor(240, 74, 80) self._alternateTextColor = None self._alternateRoles = set(( QtWidgets.QDialogButtonBox.RejectRole, QtWidgets.QDialogButtonBox.DestructiveRole, QtWidgets.QDialogButtonBox.NoRole, )) def _polishApp(self): self.polish(QtWidgets.QApplication.instance()) def buttonFont(self): return QtGui.QFont(self._buttonFont) @QtCore.pyqtSlot(QtGui.QFont) def setButtonFont(self, font): if not isinstance(font, QtGui.QFont) or font == self._buttonFont: return self._buttonFont = font self._buttonFontMetrics = QtGui.QFontMetrics(self._buttonFont) self._polishApp() def defaultButtonColor(self): return QtGui.QColor(self._defaultButtonColor) @QtCore.pyqtSlot(QtCore.Qt.GlobalColor) @QtCore.pyqtSlot(QtGui.QColor) def setDefaultButtonColor(self, color): if isinstance(color, QtCore.Qt.GlobalColor): color = QtGui.QColor(color) elif not isinstance(color, QtGui.QColor): return self._defaultButtonColor = color self._polishApp() def alternateButtonColor(self): return QtGui.QColor(self._alternateButtonColor) @QtCore.pyqtSlot(QtCore.Qt.GlobalColor) @QtCore.pyqtSlot(QtGui.QColor) def setAlternateButtonColor(self, color): if isinstance(color, QtCore.Qt.GlobalColor): color = QtGui.QColor(color) elif not isinstance(color, QtGui.QColor): return self._alternateButtonColor = color self._polishApp() def alternateRoles(self): return self._alternateRoles def setAlternateRoles(self, roles): newRoles = set() for role in roles: if isinstance(role, QtWidgets.QDialogButtonBox.ButtonRole): newRoles.add(role) if newRoles != self._alternateRoles: self._alternateRoles = newRoles self._polishApp() def setAlternateRole(self, role, activate=True): if isinstance(role, QtWidgets.QDialogButtonBox.ButtonRole): if activate and role in self._alternateRoles: self._alternateRoles.add(role) self._polishApp() elif not activate and role not in self._alternateRoles: self._alternateRoles.remove(role) self._polishApp() def defaultTextColor(self): return QtGui.QColor(self._defaultTextColor) @QtCore.pyqtSlot(QtCore.Qt.GlobalColor) @QtCore.pyqtSlot(QtGui.QColor) def setDefaultTextColor(self, color): if isinstance(color, QtCore.Qt.GlobalColor): color = QtGui.QColor(color) elif not isinstance(color, QtGui.QColor): return self._defaultTextColor = color self._polishApp() def alternateTextColor(self): return QtGui.QColor(self._alternateTextColor or self._defaultTextColor) @QtCore.pyqtSlot(QtCore.Qt.GlobalColor) @QtCore.pyqtSlot(QtGui.QColor) def setAlternateTextColor(self, color): if isinstance(color, QtCore.Qt.GlobalColor): color = QtGui.QColor(color) elif not isinstance(color, QtGui.QColor): return self._alternateTextColor = color self._polishApp() def drawControl(self, element, option, painter, widget): if element == self.CE_PushButton: isAlternate = False if widget and isinstance(widget.parent(), QtWidgets.QDialogButtonBox): role = widget.parent().buttonRole(widget) if role in self._alternateRoles: isAlternate = True elif widget.property('alternateColor'): isAlternate = True if isAlternate: color = self.alternateButtonColor() textColor = self.alternateTextColor() else: color = self.defaultButtonColor() textColor = self.defaultTextColor() if not option.state & self.State_Enabled: color.setAlpha(color.alpha() * .75) textColor.setAlpha(textColor.alpha() * .75) # switch the existing palette with a new one created from it; # this shouldn't be necessary, but better safe than sorry oldPalette = option.palette palette = QtGui.QPalette(oldPalette) palette.setColor(palette.ButtonText, textColor) # some styles use WindowText for flat buttons palette.setColor(palette.WindowText, textColor) option.palette = palette # colors that are almost black are not very affected by "lighter" if color.value() < 32: lightColor = QtGui.QColor(48, 48, 48, color.alpha()) else: lightColor = color.lighter(115) darkColor = color.darker() if option.state & self.State_MouseOver: # colors that are almost black are not very affected by "lighter" bgColor = lightColor lighterColor = lightColor.lighter(115) darkerColor = darkColor.darker(115) else: bgColor = color lighterColor = lightColor darkerColor = darkColor if option.state & self.State_Raised and not option.state & self.State_On: topLeftPen = QtGui.QPen(lighterColor) bottomRightPen = QtGui.QPen(darkerColor) elif option.state & (self.State_On | self.State_Sunken): if option.state & self.State_On: bgColor = bgColor.darker() else: bgColor = bgColor.darker(125) topLeftPen = QtGui.QPen(darkColor) bottomRightPen = QtGui.QPen(lighterColor) else: topLeftPen = bottomRightPen = QtGui.QPen(bgColor) painter.save() painter.setRenderHints(painter.Antialiasing) painter.translate(.5, .5) rect = option.rect.adjusted(0, 0, -1, -1) painter.setBrush(bgColor) painter.setPen(QtCore.Qt.NoPen) painter.drawRoundedRect(rect, 2, 2) if topLeftPen != bottomRightPen: roundRect = QtCore.QRectF(0, 0, 4, 4) painter.setBrush(QtCore.Qt.NoBrush) # the top and left borders tlPath = QtGui.QPainterPath() tlPath.arcMoveTo(roundRect.translated(0, rect.height() - 4), 225) tlPath.arcTo(roundRect.translated(0, rect.height() - 4), 225, -45) tlPath.arcTo(roundRect, 180, -90) tlPath.arcTo(roundRect.translated(rect.width() - 4, 0), 90, -45) painter.setPen(topLeftPen) painter.drawPath(tlPath) # the bottom and right borders brPath = QtGui.QPainterPath(tlPath.currentPosition()) brPath.arcTo(roundRect.translated(rect.width() - 4, 0), 45, -45) brPath.arcTo( roundRect.translated(rect.width() - 4, rect.height() - 4), 0, -90) brPath.arcTo( roundRect.translated(0, rect.height() - 4), 270, -45) painter.setPen(bottomRightPen) painter.drawPath(brPath) if option.state & self.State_HasFocus: focusColor = QtGui.QColor(textColor).darker() focusColor.setAlpha(focusColor.alpha() * .75) painter.setPen(focusColor) painter.setBrush(QtCore.Qt.NoBrush) painter.drawRoundedRect(rect.adjusted(2, 2, -2, -2), 2, 2) painter.setFont(self._buttonFont) oldMetrics = option.fontMetrics option.fontMetrics = self._buttonFontMetrics self.drawControl(self.CE_PushButtonLabel, option, painter, widget) painter.restore() # restore the original font metrics and palette option.fontMetrics = oldMetrics option.palette = oldPalette return super().drawControl(element, option, painter, widget) def sizeFromContents(self, contentsType, option, size, widget=None): if contentsType == self.CT_PushButton: if option.text: textSize = option.fontMetrics.size( QtCore.Qt.TextShowMnemonic, option.text) baseWidth = size.width() - textSize.width() baseHeight = size.height() - textSize.height() text = option.text else: baseWidth = size.width() baseHeight = size.height() text = 'XXXX' if not option.icon else '' buttonTextSize = self._buttonFontMetrics.size( QtCore.Qt.TextShowMnemonic, text) if not widget or widget.font() != QtWidgets.QApplication.font(): buttonTextSize = buttonTextSize.expandedTo( QtWidgets.QApplication.fontMetrics().size( QtCore.Qt.TextShowMnemonic, text)) margin = self.pixelMetric(self.PM_ButtonMargin, option, widget) newSize = QtCore.QSize( buttonTextSize.width() + baseWidth + margin * 2, buttonTextSize.height() + baseHeight + margin) return newSize.expandedTo( super().sizeFromContents(contentsType, option, size, widget)) return super().sizeFromContents(contentsType, option, size, widget) app = QtWidgets.QApplication(sys.argv) app.setStyle(ColorButtonStyle()) # ...
从这一点开始,您还可以添加其他属性以更好地控制样式,例如圆角矩形的半径(只需在边框图形中用变量替换每个“4”,并使用一半的变量绘制背景):
painter.drawRoundedRect(rect, self._radius / 2, self._radius / 2) if topLeftPen != bottomRightPen: roundRect = QtCore.QRectF(0, 0, self._radius, self._radius) painter.setBrush(QtCore.Qt.NoBrush) # the top and left borders tlPath = QtGui.QPainterPath() tlPath.arcMoveTo(roundRect.translated( 0, rect.height() - self._radius), 225) tlPath.arcTo(roundRect.translated( 0, rect.height() - self._radius), 225, -45)
您可以使用样式表根据自己的喜好进行设计
下面是一个独立的示例。当然,您必须使其适应您喜欢的颜色和尺寸。但这应该已经提供了一个起点
输出
它看起来是这样的:
虽然已经提供的解决方案可以很好地工作,但并不完全适用于整个应用程序,特别是如果您想要控制对话框按钮的外观
即使将样式表应用于应用程序,也需要确保在父级中正确设置选择器:例如,在另一个答案中,设置没有选择器的背景属性将清除子级的应用程序样式表继承
假设将样式表设置为应用程序,并且仔细编写了所有其他样式表集,那么对话框窗口就会出现问题
如果对话框是手动创建的,则可以通过为每个按钮指定样式表来设置替换颜色,但对于使用静态函数创建的按钮,这是不可能的
在这种情况下,唯一的可能是使用QProxyStyle。下面是一个可能的实现,它还允许设置自定义颜色和字体,并自动为对话框按钮框(取消、忽略等)的“负面”角色设置备用颜色
在本例中,我刚刚将样式应用于应用程序,但消息框是使用
information()
静态函数创建的。“备用”按钮是使用自定义属性手动设置的:button.setProperty('alternateColor', True)
从这一点开始,您还可以添加其他属性以更好地控制样式,例如圆角矩形的半径(只需在边框图形中用变量替换每个“4”,并使用一半的变量绘制背景):
相关问题 更多 >
编程相关推荐