- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试创建带有文本轮廓的标签。我只想要一个带有黑色轮廓的简单白色文本。我首先尝试在 css 中这样做 label.setStyleSheet("color:white; outline:2px black;")
但大纲没有做任何事情。
我进行了大量搜索并找到了使用 qpainter 路径的方法。但问题是文本总是被截断。
根据函数,文本应该从左下角开始,但它开始太低太左。我知道我可以通过试错找到一个点,这样它就不会被切断——你可以 -20 到高度,这对这个来说已经足够了。但它只会修复这个特定的文本!对于具有不同大小、文本或字体的任何标签,它都不会相同。
我将把最小的代码示例放在这里
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QWidget, QLabel, QMainWindow
class MainLabel(QLabel):
def __init__(self, text):
super(MainLabel, self).__init__(text)
def paintEvent(self, event):
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing)
font=QtGui.QFont()
font.setPointSize(70)
painterPath = QtGui.QPainterPath()
#how to get the right positioning for addText
painterPath.addText(0, self.height(), font,self.text())#HERE
qp.strokePath(painterPath, QtGui.QPen(QtGui.QColor(0,0,0), 6))
qp.fillPath(painterPath, QtGui.QColor(255,255,255))
qp.end()
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.centralWidget=QWidget(self)
self.setCentralWidget(self.centralWidget)
self.lay = QtWidgets.QVBoxLayout()
self.centralWidget.setLayout(self.lay)
self.label = MainLabel("text gets cut off")
self.label.setStyleSheet("font-size:70pt;color:white; outline:2px black;")
self.lay.addWidget(self.label)
self.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
这是一个很常见的事情,我几乎到处都能看到,但是在 PYQT 中没有一个简单的函数可以解决这个问题而不引起更多问题吗?所以普通的Qlabel会自动处理定位,但如果你想要文本轮廓你就得放弃!
所以我想问的是,如果这是获得文本轮廓的唯一方法,如何像普通 Qlabel 一样找到正确的定位,否则如果有其他更好的方法请告诉我。
最佳答案
仅仅因为没有方便的功能或样式表属性并不意味着没有一致的解决方案!
设置文本的基线位置需要考虑许多属性:QLabel 的几何形状、文本的 boundingRect、对齐方式、缩进、字体规范。轮廓文本总体上将比相同磅值的常规文本大,因此重新实现了 sizeHint
和 minimumSizeHint
来解决这个问题。文档解释了如何 indent计算并与对齐一起使用。文本和字符的几何形状、上升、下降和方位角是从 QFontMetrics 获得的。有了这些信息,就可以确定 QPainterPath.addText
的位置来模拟 QLabel。
import sys, math
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class OutlinedLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.w = 1 / 25
self.mode = True
self.setBrush(Qt.white)
self.setPen(Qt.black)
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.indent() == -1:
if self.frameWidth():
indent = (metrics.boundingRect('x').width() + w * 2) / 2
else:
indent = w
else:
indent = self.indent()
if self.alignment() & Qt.AlignLeft:
x = rect.left() + indent - min(metrics.leftBearing(self.text()[0]), 0)
elif self.alignment() & Qt.AlignRight:
x = rect.x() + rect.width() - indent - tr.width()
else:
x = (rect.width() - tr.width()) / 2
if self.alignment() & Qt.AlignTop:
y = rect.top() + indent + metrics.ascent()
elif self.alignment() & Qt.AlignBottom:
y = rect.y() + rect.height() - indent - metrics.descent()
else:
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)
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)
您可以使用setBrush
和setPen
设置OutlinedLabel
填充和轮廓颜色。默认为带有黑色轮廓的白色文本。轮廓粗细基于字体的点大小,默认比例为 1/25(即 25pt 字体将具有 1px 粗轮廓)。使用 setOutlineThickness
来改变它。如果您想要一个不基于点大小(例如 3px)的固定轮廓,请调用 setScaledOutlineMode(False)
和 setOutlineThickness(3)
。
此类仅支持左/右/上/下/居中对齐的单行纯文本字符串。如果您想要其他 QLabel 功能,如超链接、自动换行、省略文本等,也需要实现这些功能。但在这些情况下,您很可能不会使用文本大纲。
这是一个例子,表明它适用于各种标签:
class Template(QWidget):
def __init__(self):
super().__init__()
vbox = QVBoxLayout(self)
label = OutlinedLabel('Lorem ipsum dolor sit amet consectetur adipiscing elit,')
label.setStyleSheet('font-family: Monaco; font-size: 20pt')
vbox.addWidget(label)
label = OutlinedLabel('sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.')
label.setStyleSheet('font-family: Helvetica; font-size: 30pt; font-weight: bold')
vbox.addWidget(label)
label = OutlinedLabel('Ut enim ad minim veniam,', alignment=Qt.AlignCenter)
label.setStyleSheet('font-family: Comic Sans MS; font-size: 40pt')
vbox.addWidget(label)
label = OutlinedLabel('quis nostrud exercitation ullamco laboris nisi ut')
label.setStyleSheet('font-family: Arial; font-size: 50pt; font-style: italic')
vbox.addWidget(label)
label = OutlinedLabel('aliquip ex ea commodo consequat.')
label.setStyleSheet('font-family: American Typewriter; font-size: 60pt')
label.setPen(Qt.red)
vbox.addWidget(label)
label = OutlinedLabel('Duis aute irure dolor', alignment=Qt.AlignRight)
label.setStyleSheet('font-family: Luminari; font-size: 70pt')
label.setPen(Qt.red); label.setBrush(Qt.black)
vbox.addWidget(label)
label = OutlinedLabel('in reprehenderit')
label.setStyleSheet('font-family: Zapfino; font-size: 80pt')
label.setBrush(Qt.red)
vbox.addWidget(label)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Template()
window.show()
sys.exit(app.exec_())
现在 Qt 实际上发挥了重要作用,因为您可以从中获得更多,而不仅仅是使用所有 QBrush/QPen 选项的纯色文本和轮廓:
class Template(QWidget):
def __init__(self):
super().__init__()
vbox = QVBoxLayout(self)
text = 'Felicitations'
label = OutlinedLabel(text)
linearGrad = QLinearGradient(0, 1, 0, 0)
linearGrad.setCoordinateMode(QGradient.ObjectBoundingMode)
linearGrad.setColorAt(0, QColor('#0fd850'))
linearGrad.setColorAt(1, QColor('#f9f047'))
label.setBrush(linearGrad)
label.setPen(Qt.darkGreen)
vbox.addWidget(label)
label = OutlinedLabel(text)
radialGrad = QRadialGradient(0.3, 0.7, 0.05)
radialGrad.setCoordinateMode(QGradient.ObjectBoundingMode)
radialGrad.setSpread(QGradient.ReflectSpread)
radialGrad.setColorAt(0, QColor('#0250c5'))
radialGrad.setColorAt(1, QColor('#2575fc'))
label.setBrush(radialGrad)
label.setPen(QColor('Navy'))
vbox.addWidget(label)
label = OutlinedLabel(text)
linearGrad.setStart(0, 0); linearGrad.setFinalStop(1, 0)
linearGrad.setColorAt(0, Qt.cyan); linearGrad.setColorAt(1, Qt.magenta)
label.setPen(QPen(linearGrad, 1)) # pen width is ignored
vbox.addWidget(label)
label = OutlinedLabel(text)
linearGrad.setFinalStop(1, 1)
for x in [(0, '#231557'), (0.29, '#44107A'), (0.67, '#FF1361'), (1, '#FFF800')]:
linearGrad.setColorAt(x[0], QColor(x[1]))
label.setBrush(linearGrad)
label.setPen(QPen(QBrush(QColor('RoyalBlue'), Qt.Dense4Pattern), 1))
label.setOutlineThickness(1 / 15)
vbox.addWidget(label)
label = OutlinedLabel(text)
label.setBrush(QBrush(Qt.darkBlue, Qt.BDiagPattern))
label.setPen(Qt.darkGray)
vbox.addWidget(label)
label = OutlinedLabel(text, styleSheet='background-color: black')
label.setBrush(QPixmap('paint.jpg'))
label.setPen(QColor('Lavender'))
vbox.addWidget(label)
self.setStyleSheet('''
OutlinedLabel {
font-family: Ubuntu;
font-size: 60pt;
font-weight: bold;
}''')
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Template()
window.show()
sys.exit(app.exec_())
请注意,我选择使用 setBrush
/setPen
方法将 OutlinedLabel 视为 QGraphicsItem。如果你想为文本颜色使用样式表,请使用 qp.fillPath(path, self.palette().text())
替代调用 QPainter.strokePath
然后调用 QPainter.fillPath
的另一个选项是使用 QPainterPathStroker 生成文本路径的可填充轮廓,但我注意到它更慢.我只会用它来调整非常小的文本的清晰度,方法是为笔触设置比笔更大的宽度。要尝试将 paintEvent
中的最后 5 行替换为:
qp.setBrush(self.brush)
self.pen.setWidthF(w)
qp.setPen(self.pen)
stroker = QPainterPathStroker()
stroker.setWidth(w)
qp.drawPath(stroker.createStroke(path).united(path))
关于python - QLabel 文本轮廓的正确定位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64290561/
我有一个不规则形状的元素(比方说图标)。 我想要围绕它的某种轮廓,以符合特定颜色的形状。此轮廓的颜色必须均匀地围绕形状,即与形状各处的距离相同,并且没有颜色渐变。 我发现使用的是 css 选项 fil
这部分代码我总是出错 &contours = ((contours.h_next) -> h_next); contours.h_next = ((contours.h_next) -> h_next
我通过 css (:after) 创建了 3 个圆圈,使用一些背景颜色,边框看起来不规则。有什么解决办法吗? 在这里您可以看到问题:https://flowersliving.com/cpt_01/a
使用这个: background: -moz-linear-gradient(315deg, transparent 10px, black 10px); 如何在不使用 border 的情况下围绕它创
我想计算二元 NxM 矩阵中某个形状周围的凸包。凸包算法需要一个坐标列表,所以我采用 numpy.argwhere(im) 来获得所有形状点坐标。然而,这些点中的大多数对凸包没有贡献(它们位于形状的内
如何删除从下拉菜单中选择元素时显示的虚线边框/轮廓? 您可以看到显示了虚线边框/轮廓,我想删除它(在 Firefox 中截取的屏幕截图)。 尝试下面的解决方案并没有删除它: select:focus,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎是题外话,因为它缺乏足够的信息来诊断问题。 更详细地描述您的问题或include a min
我正在使用 Qt4 GraphicsView 框架绘制一些多边形,并且允许用户放大和缩小绘图。我希望多边形随着用户在 View 中更改缩放级别(比例)而变得越来越小,但是有没有办法使轮廓厚度始终保持不
我在 C# 中有一个 Vector3 点列表,我需要计算这些点的凹轮廓。确实有很多引用资料,尤其是 -convex- 分辨率(我已经成功实现了,多亏了 graham 的算法), 但是,由于我现在需要有
注: r 中的解决方案, python , java ,或者如果需要,c++或 c#是需要的。 我正在尝试根据运输时间绘制轮廓。更清楚地说,我想将具有相似旅行时间(比如说 10 分钟间隔)的点聚集到特
假设我在图像上找到了轮廓。在图像 2 上找到此轮廓位置的最佳方法是什么? 我看到两个选项:要么我用白线绘制轮廓并匹配图像 2 上的图像,要么我以某种方式(这甚至可能吗?)直接匹配图像 2 上的轮廓。
我一直在研究细菌的图像,希望从图像中获取细菌的数量,还需要根据特定的形状和大小对细菌进行分类。 我正在使用opencv python。现在,我使用轮廓法。 contours,hierarchy
我无法区分以下两个轮廓。 cv2.contourArea两者的值相同。在Python中有什么功能可以区分它们吗? 最佳答案 要区分填充轮廓和未填充轮廓,可以在使用 cv2.findContours 查
是否可以根据 Activity 配置文件的某些表达式来注册bean前任。 @Profile(!prod) @Profile(name!="test") 我有一种情况,我需要根据许多不同的条件配
我有一个由多个 CAShapeLayer 组成的 3D 相似图形对象。必须抚摸所有形状(天花板和墙壁)。有些形状共享一条边 - 这似乎是问题的根源。 然而,轮廓似乎是围绕另一个形状的现有轮廓绘制的。所
有谁知道,是否可以在用户使用顺序导航(TAB 按钮)时在输入元素周围显示轮廓,并在用户用鼠标单击此输入元素时隐藏轮廓?有没有人实现过这种行为? 我在 CSS 文件中的 :focus 选择器上使用这个属
这是我在 StackOverflow 上的第一个问题,所以我会尝试以正确的方式格式化它。 基本上,我有一个带有边框和轮廓的 div。悬停时,div 也会有一个阴影,当然,它应该在轮廓之外。这适用于所有
我在 Opencv 2.9 (C++) 中使用 findContours。我得到的是一个 vector> contours,它描述了我的轮廓。假设我有一个矩形,其轮廓存储在 vector 中。接下来我
我有一个 div,它有附加的子 div,定位在父 div 之外。 我希望父 div 有一个轮廓 onclick,但轮廓延伸到子 div 周围。 有没有办法让轮廓完全围绕父 div。 我不能使用边框,因
我正在尝试在彩色图标周围设置实线边框。 应该足够直截了当,显然它适用于字形,但我无法让它适用于 我试过... // like this fiddle: http://jsfiddle.net/9s
我是一名优秀的程序员,十分优秀!