Как создать обводку на тексте внутри QPushButton
Мне нужен способ, при котором на любом цвете кнопки можно было прочитать текст этой кнопки.
Цвета задаются не статически (не прописаны в коде), а пользователем. Потому возможны ситуации когда например на чёрный текст будет приходится тёмно-синий цвет и наоборот, на белый текст, яркие цвета.
Установить прозрачность через rgba тоже не вариант, цвет задаётся в HEX-формате. Потому как вариант - прописать обводку для текста.
border-color через setStyleSheet почему то не работает.
Так же пробовал через QtWidgets.QGraphicsDropShadowEffect, но в таком случае тень накладывается только на саму кнопку, а не на текст.
Гугл только про обводку QLabel подсказывает. Помогите с решением.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtGui import QColor
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class WinFrame(QMainWindow):
def __init__(self):
super().__init__()
self.win = QtWidgets.QWidget(self)
self.win.setObjectName("page_video")
self.setCentralWidget(self.win)
self.gridLayout = QtWidgets.QGridLayout(self.win)
userColor = 'e5ff70'
self.tag = QPushButton("Рандомная кнопка")
self.tag.setStyleSheet(
f"background-color: #{userColor}; color: white; border-color: black;")
shadow = QtWidgets.QGraphicsDropShadowEffect(
self, blurRadius=14.0, color=QColor("#a8a7a7"), offset=QtCore.QPointF(0.0, 0.0))
self.tag.setGraphicsEffect(shadow)
self.gridLayout.addWidget(self.tag)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = WinFrame()
window.show()
window.resize(800, 600)
sys.exit(app.exec_())
Ответы (1 шт):
Как вариант:
import sys, math
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.Qt import *
class PushButton(QPushButton):
def __init__(self, userColor, *args, **kwargs):
super().__init__(*args, **kwargs)
self.w = 1 / 25
self.mode = True
self.setBrush(Qt.white)
self.setPen(Qt.black)
self.userColor = userColor
def scaledOutlineMode(self):
return self.mode
def setScaledOutlineMode(self, state):
self.mode = state
def outlineThickness(self):
return self.w * self.font().pointSize() if self.mode else self.w
def setOutlineThickness(self, value):
self.w = value
def setBrush(self, brush):
if not isinstance(brush, QBrush):
brush = QBrush(brush)
self.brush = brush
def setPen(self, pen):
if not isinstance(pen, QPen):
pen = QPen(pen)
pen.setJoinStyle(Qt.RoundJoin)
self.pen = pen
def sizeHint(self):
w = math.ceil(self.outlineThickness() * 2)
return super().sizeHint() + QSize(w, w)
def minimumSizeHint(self):
w = math.ceil(self.outlineThickness() * 2)
return super().minimumSizeHint() + QSize(w, w)
def paintEvent(self, event):
w = self.outlineThickness()
rect = self.rect()
metrics = QFontMetrics(self.font())
tr = metrics.boundingRect(self.text()).adjusted(0, 0, w, w)
if self.width():
indent = (metrics.boundingRect('x').width() + w * 2) / 2
else:
indent = w
x = (rect.width() - tr.width()) / 2
y = (rect.height() + metrics.ascent() - metrics.descent()) / 2
path = QPainterPath()
path.addText(x, y, self.font(), self.text())
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(Qt.blue)
qp.setBrush(QColor(f'#{self.userColor}'))
rectf = QRectF(rect)
qp.drawRoundedRect(rectf, 6, 6)
self.pen.setWidthF(w * 2)
qp.strokePath(path, self.pen)
if 1 < self.brush.style() < 15:
qp.fillPath(path, self.palette().window())
qp.fillPath(path, self.brush)
class WinFrame(QMainWindow):
def __init__(self):
super().__init__()
self.centralWidget = QtWidgets.QWidget(self)
self.setCentralWidget(self.centralWidget)
userColor = 'e5ff70'
button = PushButton(userColor, 'Рандомная кнопка')
button.clicked.connect(lambda: print(f'{button.text()}'))
button.setStyleSheet('font-family: Zapfino; font-size: 70pt')
# попробуйте раскомментировть строку ниже
# button.setBrush(QColor(f'#{userColor}'))
vbox = QVBoxLayout(self.centralWidget)
vbox.addWidget(button)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = WinFrame()
window.show()
sys.exit(app.exec_())
