WAL*_*L-E 2 python outline pyqt5
我正在尝试创建一个带有文本轮廓的标签。我只想要一个带有黑色轮廓的简单白色文本。我首先尝试在 css 中这样做,就像这样label.setStyleSheet("color:white; outline:2px black;")
\n但是大纲没有\xe2\x80\x99 做任何事情。
我做了很多搜索并找到了使用 qpainter 路径来完成此操作的方法。但问题是文本总是被切断。
根据该功能,文本应该从左下角开始,但它开始得太低且太左。我知道我可以通过尝试错误找到一个点,这样它就不会\xe2\x80\x99t 被切断——你可以-20 到高度,对于这个来说就足够了。但它只会修复这个特定的文本!对于任何具有不同大小、文本或字体的标签来说,它都不会相同。
\n我将在这里放置最小的代码示例
\nfrom PyQt5 import QtCore, QtGui, QtWidgets\nfrom PyQt5.QtWidgets import QWidget, QLabel, QMainWindow\n\n\nclass MainLabel(QLabel):\n def __init__(self, text):\n super(MainLabel, self).__init__(text)\n\n def paintEvent(self, event):\n qp = QtGui.QPainter()\n qp.begin(self)\n qp.setRenderHint(QtGui.QPainter.Antialiasing)\n font=QtGui.QFont()\n font.setPointSize(70)\n painterPath = QtGui.QPainterPath()\n #how to get the right positioning for addText\n painterPath.addText(0, self.height(), font,self.text())#HERE\n qp.strokePath(painterPath, QtGui.QPen(QtGui.QColor(0,0,0), 6))\n qp.fillPath(painterPath, QtGui.QColor(255,255,255))\n qp.end()\n\n\nclass MainWindow(QMainWindow):\n def __init__(self):\n super(MainWindow, self).__init__()\n self.centralWidget=QWidget(self)\n self.setCentralWidget(self.centralWidget)\n self.lay = QtWidgets.QVBoxLayout()\n self.centralWidget.setLayout(self.lay)\n self.label = MainLabel("text gets cut off")\n self.label.setStyleSheet("font-size:70pt;color:white; outline:2px black;")\n self.lay.addWidget(self.label)\n self.show()\n\n\nif __name__ == \'__main__\':\n import sys\n app = QtWidgets.QApplication(sys.argv)\n w = MainWindow()\n sys.exit(app.exec_())\nRun Code Online (Sandbox Code Playgroud)\n这是一个很常见的事情,我几乎到处都可以看到,但 PYQT 中没有简单的函数可以做到这一点而不引起更多问题吗?所以普通的 Qlabel 会自动处理定位,但如果你想要文本轮廓,你就必须放弃它!
\n所以我问如何找到像普通 Qlabel 一样的正确定位,如果这是获得文本轮廓的唯一方法,否则如果有其他更好的方法,请告诉我。
\n仅仅因为没有方便的函数或样式表属性并不意味着没有一致的解决方案!
\n设置文本的基线位置需要考虑许多属性:QLabel 的几何形状、文本的boundingRect、对齐方式、缩进、字体规格。轮廓文本总体上比相同磅值的常规文本更大,因此重新实现sizeHint和minimumSizeHint来解决这一问题。该文档解释了如何计算缩进并与对齐一起使用。文本和字符的几何形状、上升、下降和方位角是从 QFontMetrics 获得的。QPainterPath.addText有了这些信息,就可以确定模拟 QLabel 的位置。
import sys, math\nfrom PyQt5.QtWidgets import *\nfrom PyQt5.QtCore import *\nfrom PyQt5.QtGui import *\n \nclass OutlinedLabel(QLabel):\n \n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self.w = 1 / 25\n self.mode = True\n self.setBrush(Qt.white)\n self.setPen(Qt.black)\n\n def scaledOutlineMode(self):\n return self.mode\n\n def setScaledOutlineMode(self, state):\n self.mode = state\n\n def outlineThickness(self):\n return self.w * self.font().pointSize() if self.mode else self.w\n\n def setOutlineThickness(self, value):\n self.w = value\n\n def setBrush(self, brush):\n if not isinstance(brush, QBrush):\n brush = QBrush(brush)\n self.brush = brush\n\n def setPen(self, pen):\n if not isinstance(pen, QPen):\n pen = QPen(pen)\n pen.setJoinStyle(Qt.RoundJoin)\n self.pen = pen\n\n def sizeHint(self):\n w = math.ceil(self.outlineThickness() * 2)\n return super().sizeHint() + QSize(w, w)\n \n def minimumSizeHint(self):\n w = math.ceil(self.outlineThickness() * 2)\n return super().minimumSizeHint() + QSize(w, w)\n \n def paintEvent(self, event):\n w = self.outlineThickness()\n rect = self.rect()\n metrics = QFontMetrics(self.font())\n tr = metrics.boundingRect(self.text()).adjusted(0, 0, w, w)\n if self.indent() == -1:\n if self.frameWidth():\n indent = (metrics.boundingRect(\'x\').width() + w * 2) / 2\n else:\n indent = w\n else:\n indent = self.indent()\n\n if self.alignment() & Qt.AlignLeft:\n x = rect.left() + indent - min(metrics.leftBearing(self.text()[0]), 0)\n elif self.alignment() & Qt.AlignRight:\n x = rect.x() + rect.width() - indent - tr.width()\n else:\n x = (rect.width() - tr.width()) / 2\n \n if self.alignment() & Qt.AlignTop:\n y = rect.top() + indent + metrics.ascent()\n elif self.alignment() & Qt.AlignBottom:\n y = rect.y() + rect.height() - indent - metrics.descent()\n else:\n y = (rect.height() + metrics.ascent() - metrics.descent()) / 2\n\n path = QPainterPath()\n path.addText(x, y, self.font(), self.text())\n qp = QPainter(self)\n qp.setRenderHint(QPainter.Antialiasing)\n\n self.pen.setWidthF(w * 2)\n qp.strokePath(path, self.pen)\n if 1 < self.brush.style() < 15:\n qp.fillPath(path, self.palette().window())\n qp.fillPath(path, self.brush)\nRun Code Online (Sandbox Code Playgroud)\n您可以使用和设置OutlinedLabel填充颜色和轮廓颜色。默认为带有黑色轮廓的白色文本。轮廓粗细基于字体的磅值,默认比例为 1/25(即 25pt 字体将具有 1px 粗轮廓)。用来改变它。如果您想要一个不基于点大小(例如 3px)的固定轮廓,请调用和。setBrushsetPensetOutlineThicknesssetScaledOutlineMode(False)setOutlineThickness(3)
此类仅支持左/右/上/下/中心对齐的单行纯文本字符串。如果您想要其他 QLabel 功能,例如超链接、自动换行、省略文本等,也需要实现这些功能。但在这些情况下您很可能\xe2\x80\x99 不会使用文本轮廓。
\n这是一个示例,表明它适用于各种标签:
\n\nclass Template(QWidget):\n\n def __init__(self):\n super().__init__()\n vbox = QVBoxLayout(self)\n label = OutlinedLabel(\'Lorem ipsum dolor sit amet consectetur adipiscing elit,\')\n label.setStyleSheet(\'font-family: Monaco; font-size: 20pt\')\n vbox.addWidget(label)\n\n label = OutlinedLabel(\'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\')\n label.setStyleSheet(\'font-family: Helvetica; font-size: 30pt; font-weight: bold\')\n vbox.addWidget(label)\n\n label = OutlinedLabel(\'Ut enim ad minim veniam,\', alignment=Qt.AlignCenter)\n label.setStyleSheet(\'font-family: Comic Sans MS; font-size: 40pt\')\n vbox.addWidget(label)\n\n label = OutlinedLabel(\'quis nostrud exercitation ullamco laboris nisi ut\')\n label.setStyleSheet(\'font-family: Arial; font-size: 50pt; font-style: italic\')\n vbox.addWidget(label)\n\n label = OutlinedLabel(\'aliquip ex ea commodo consequat.\')\n label.setStyleSheet(\'font-family: American Typewriter; font-size: 60pt\')\n label.setPen(Qt.red)\n vbox.addWidget(label)\n\n label = OutlinedLabel(\'Duis aute irure dolor\', alignment=Qt.AlignRight)\n label.setStyleSheet(\'font-family: Luminari; font-size: 70pt\')\n label.setPen(Qt.red); label.setBrush(Qt.black)\n vbox.addWidget(label)\n\n label = OutlinedLabel(\'in reprehenderit\')\n label.setStyleSheet(\'font-family: Zapfino; font-size: 80pt\')\n label.setBrush(Qt.red)\n vbox.addWidget(label)\n\n\nif __name__ == \'__main__\':\n app = QApplication(sys.argv)\n window = Template()\n window.show()\n sys.exit(app.exec_())\nRun Code Online (Sandbox Code Playgroud)\n现在,Qt 实际上发挥了重要作用,因为您可以通过所有 QBrush/QPen 选项获得比纯色文本和轮廓更多的内容:
\n\nclass Template(QWidget):\n\n def __init__(self):\n super().__init__() \n vbox = QVBoxLayout(self)\n text = \'Felicitations\'\n \n label = OutlinedLabel(text)\n linearGrad = QLinearGradient(0, 1, 0, 0)\n linearGrad.setCoordinateMode(QGradient.ObjectBoundingMode)\n linearGrad.setColorAt(0, QColor(\'#0fd850\'))\n linearGrad.setColorAt(1, QColor(\'#f9f047\'))\n label.setBrush(linearGrad)\n label.setPen(Qt.darkGreen)\n vbox.addWidget(label)\n\n label = OutlinedLabel(text)\n radialGrad = QRadialGradient(0.3, 0.7, 0.05)\n radialGrad.setCoordinateMode(QGradient.ObjectBoundingMode)\n radialGrad.setSpread(QGradient.ReflectSpread)\n radialGrad.setColorAt(0, QColor(\'#0250c5\'))\n radialGrad.setColorAt(1, QColor(\'#2575fc\'))\n label.setBrush(radialGrad)\n label.setPen(QColor(\'Navy\'))\n vbox.addWidget(label)\n \n label = OutlinedLabel(text)\n linearGrad.setStart(0, 0); linearGrad.setFinalStop(1, 0)\n linearGrad.setColorAt(0, Qt.cyan); linearGrad.setColorAt(1, Qt.magenta)\n label.setPen(QPen(linearGrad, 1)) # pen width is ignored\n vbox.addWidget(label)\n\n label = OutlinedLabel(text)\n linearGrad.setFinalStop(1, 1)\n for x in [(0, \'#231557\'), (0.29, \'#44107A\'), (0.67, \'#FF1361\'), (1, \'#FFF800\')]:\n linearGrad.setColorAt(x[0], QColor(x[1]))\n label.setBrush(linearGrad)\n label.setPen(QPen(QBrush(QColor(\'RoyalBlue\'), Qt.Dense4Pattern), 1))\n label.setOutlineThickness(1 / 15)\n vbox.addWidget(label)\n\n label = OutlinedLabel(text)\n label.setBrush(QBrush(Qt.darkBlue, Qt.BDiagPattern))\n label.setPen(Qt.darkGray)\n vbox.addWidget(label)\n\n label = OutlinedLabel(text, styleSheet=\'background-color: black\')\n label.setBrush(QPixmap(\'paint.jpg\'))\n label.setPen(QColor(\'Lavender\'))\n vbox.addWidget(label)\n \n self.setStyleSheet(\'\'\'\n OutlinedLabel {\n font-family: Ubuntu;\n font-size: 60pt;\n font-weight: bold;\n }\'\'\')\n\n\nif __name__ == \'__main__\':\n app = QApplication(sys.argv)\n window = Template()\n window.show()\n sys.exit(app.exec_())\nRun Code Online (Sandbox Code Playgroud)\nsetBrush请注意,我\xe2\x80\x99选择使用/方法将 OutlinedLabel 视为 QGraphicsItem setPen。如果您想使用样式表作为文本颜色,请填充路径qp.fillPath(path, self.palette().text())
另一种选择而不是调用QPainter.strokePaththenQPainter.fillPath是使用 QPainterPathStroker 生成文本路径的可填充轮廓,但我注意到它的速度较慢。我只会用它来调整非常小的文本的清晰度,方法是将笔划设置为比笔更大的宽度。要尝试将最后 5 行替换为paintEvent:
qp.setBrush(self.brush)\nself.pen.setWidthF(w)\nqp.setPen(self.pen)\nstroker = QPainterPathStroker()\nstroker.setWidth(w)\nqp.drawPath(stroker.createStroke(path).united(path))\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2669 次 |
| 最近记录: |