如何使标签文本轮廓化并适合标签的大小

Posted

技术标签:

【中文标题】如何使标签文本轮廓化并适合标签的大小【英文标题】:How to make label text outlined AND fit the size of the label 【发布时间】:2021-04-14 14:20:02 【问题描述】:

如何使标签文本被勾勒出来(以便在透明 Widget 上获得更好的可见性)并适合标签(根据函数 setWordWrap (True)?有一些示例说明如何做一个或另一个,但从不两者兼而有之。

透明小部件上的静态标签文本的基本示例是:

import sys

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class Application(QWidget):
    def __init__(self):
        super().__init__()
        screen_size = QWidget.screen(self).size()
        screen_width = screen_size.width()
        screen_height = screen_size.height()
        widget_width = screen_width * 0.30


        self.setGeometry(100, 100, widget_width, screen_height)
        self.move(screen_width - widget_width, 0)
        self.setAttribute(Qt.WA_TransparentForMouseEvents)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
                            | Qt.CustomizeWindowHint | Qt.Window)

        l1 = QLabel(self)
        l1.setWordWrap(True)
        l1.setGeometry(0, 0, widget_width, screen_height)
        l1.setFont(QFont('Arial', 22))
        l1.setStyleSheet('color:rgb(0,255,0)')
        l1.setText('Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello')


def render_the_app():
    app = QApplication(sys.argv)
    window = Application()
    window.setAttribute(Qt.WA_TranslucentBackground)
    window.show()


    app.exec_()


render_the_app()

此代码示例将呈现绿色文本“Hello Hello ...”并呈现为: 在透明小部件上换行文本示例:

【问题讨论】:

感谢@eyllanesc 编辑问题。对于同样的错误,我深表歉意,但我不知道如何让这张图片看起来像你做的那样漂亮 注意:我建议您不要再做同样的事情(重新发布相同的帖子),因为系统可能会阻止创建帖子的能力。 知道了。由于作者和审稿人之间的交流有限——我仍然不知道其他 [已关闭] 帖子会发生什么,以及是否有人会重新打开。我进行了编辑并使其简短明了。与我在 SO 上看到的许多其他帖子相比,我觉得在编辑后我的帖子至少足够好,并且比许多帖子好。但是我看不到是不是有人审核了还是觉得不好,或者没有人再审核了,我需要等待更长的时间。 您多久之前改进了您的帖子?最多一天,你认为那是很长的时间吗?不,所以你必须学会​​更有耐心。如果您不想耐心等待,请从头开始分析您的帖子,以免最终关闭。建议想发帖的人花点时间写(小时),分析自己是否符合本站规则。 @eyllanesc 这很公平。第一篇文章的审核速度给我留下了深刻的印象(15-20 分钟内),所以在编辑后 12 个多小时后,我开始感到紧张。您也知道,如果您沉迷于某个想法但找不到解决方案 - 您可能会失去耐心。这不是借口,我会从中吸取教训。感谢您的反馈 【参考方案1】:

使用画家路径是一个很好的解决方案,但它不允许对内容进行更精细的控制,特别是考虑到基于文本的小部件还应该提供正确的大小提示,并且可能允许自动换行。

另一方面,QTextDocument 被任何使用文本的 QWidget 子类(有时公开,如 QTextEdit,其他内部,如 QLabel)提供大纲功能,因此可能的解决方案是创建一个类部分模仿 QLabel,提供正确的大小提示和自动换行。

class Test(QtWidgets.QWidget):
    _outlinePen = _alignment = None
    def __init__(self, text='', parent=None, **kwargs):
        super().__init__(parent)
        self.doc = QtGui.QTextDocument()
        self._reference = self.doc.clone()
        self.doc.contentsChanged.connect(self._rebuildReference)

        self._text = text
        self._outlineColor = QtGui.QColor(kwargs.get('outlineColor'))
        self._outlineWidth = kwargs.get('outlineWidth', 0)

        if text:
            self.doc.setPlainText(text)
            self.updateContents()

    def _rebuildReference(self):
        self._reference = self.doc.clone()

    def updateContents(self):
        cursor = QtGui.QTextCursor(self.doc)
        cursor.select(cursor.Document)
        blockFmt = cursor.blockFormat()
        blockFmt.setAlignment(self.alignment())
        cursor.setBlockFormat(blockFmt)
        charFmt = cursor.charFormat()
        charFmt.setFont(self.font())

        outlinePen = self.outlinePen()
        if outlinePen:
            charFmt.setTextOutline(outlinePen)

        cursor.setCharFormat(charFmt)
        self.updateGeometry()
        self.adjustSize()

    def text(self):
        return self._text

    def setText(self, text):
        if self._text == text:
            return
        self.doc.setPlainText(text)
        self.updateContents()

    def outlinePen(self):
        if isinstance(self._outlineColor, QtGui.QColor) and self._outlineColor.isValid():
            pen = QtGui.QPen(self._outlineColor)
            pen.setWidthF(self._outlineWidth or self.fontMetrics().lineWidth() * .25)
            return pen

    def setOutlinePen(self, pen):
        self._outlineColor = pen.brush().color()
        self._outlineWidth = pen.widthF()
        self.updateContents()

    def outlineColor(self):
        return self._outlineColor

    def setOutlineColor(self, color):
        if self._outlineColor != color:
            self._outlineColor = color
            self.updateContents()

    def outlineWidth(self):
        return self._outlineWidth

    def setOutlineWidth(self, width):
        if self._outlineWidth != width:
            self._outlineWidth = width
            self.updateContents()

    def alignment(self):
        alignment = self._alignment
        if not isinstance(alignment, (QtCore.Qt.Alignment, QtCore.Qt.AlignmentFlag)):
            alignment = QtCore.Qt.AlignTop
            if self.layoutDirection() == QtCore.Qt.LeftToRight:
                alignment |= QtCore.Qt.AlignLeft
            else:
                alignment |= QtCore.Qt.AlignRight
        return alignment

    def setAlignment(self, alignment):
        if self._alignment != alignment:
            self._alignment = alignment
            self.updateContents()

    def changeEvent(self, event):
        if event.type() == event.FontChange:
            self.updateContents()

    def sizeHint(self):
        if self.isVisible():
            doc = self._reference
            doc.setTextWidth(self.width())
        else:
            doc = self.doc
        return doc.size().toSize()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        self._reference.setTextWidth(self.width())
        self._reference.drawContents(qp, QtCore.QRectF(self.rect()))

【讨论】:

谢谢!我对 PyQt 很陌生,几乎不了解它的概念。将测试您的解决方案 我尝试了我的理解,但无法使其工作。它打印文本,但我无法让它进行换行或大纲。所以它只在一行中给我黑色文本。 我建议您使用我的代码原样尝试,无需任何修改,以查看其结果。请注意,Qt.WA_TranslucentBackground 属性可能是一个问题(我无法对其进行测试)。首先,按原样尝试(作为没有半透明属性的标准小部件),只是为了看看轮廓是否有效。然后,可能需要进行一些调整:半透明实现并不像看起来那样“透明”(双关语)。我强烈建议您使用循序渐进的方法,而不是试图立即使我的代码适应您的代码。

以上是关于如何使标签文本轮廓化并适合标签的大小的主要内容,如果未能解决你的问题,请参考以下文章

如何使 ScrollView 子项适合 Nativescript-Vue 中 ScrollView 的大小?

iPhone - 调整图像和两个标签的大小以适合屏幕

如何在适合视图的同时使文本大小一致

如何使用自动布局调整视图大小以适合标签子视图?

如何使标签的背景图片与标签的框架大小相适应?

动态调整文本大小以使整个文本行适合文本字段