有没有比使用RegExp更好的方法在QToolTip中自动换行文本?

rav*_*vil 13 c++ qt

所以问题在于标题.QToolTip似乎没有提供wordwraop功能.但是,使用正则表达式可以用\n替换第N个空格,但我想知道是否有人建议更好的溶剂.具体来说,我的方法问题是它不考虑文本的长度.例如,我希望更长的文本形成更宽的段落.

dab*_*aid 21

如果工具提示中的文本是富文本,则会自动进行自动换行.

这是一个简单的例子,将字体设置为黑色使其成为"富文本",因此它会被包装.省略字体声明意味着工具提示将是纯文本并扩展屏幕的整个长度.

QString toolTip = QString("<FONT COLOR=black>");
toolTip += ("I am the very model of a modern major general, I've information vegetable animal and mineral, I know the kinges of England and I quote the fights historical from Marathon to Waterloo in order categorical...");
toolTip += QString("</FONT>");
widget->setToolTip(sToolTip);
Run Code Online (Sandbox Code Playgroud)

当然,对于此示例,工具提示的宽度取决于平台.

Qt bug跟踪器中有一个关于此问题的新建议:https://bugreports.qt.io/browse/QTBUG-41051.它还要求宽度可以更改.

  • 注意:如果工具提示的背景颜色为黑色= P,则会产生不良结果. (3认同)

Mat*_*hew 8

替代答案:<nobr>在工具提示的开头使用以指定将定义宽度的文本部分.例如:

<nobr>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed</nobr>
do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.
Run Code Online (Sandbox Code Playgroud)

之间的文本<nobr></nobr>将强制最小宽度.其余的将相应地包装.(如果您对Qt使用的默认宽度不满意,这会很有帮助,这在我的经验中往往过于狭窄.)


Cec*_*rry 7

从技术上讲,该问题的普遍答案足以满足短期技术要求(也称为:当您仅按条件使用时需要工具提示),但远远不能满足通用解决方案的要求。

无论如何,“ <font> ... </ font>”出了什么问题?

如果您不介意在整个应用程序中将所有工具提示文本手动嵌入HTML标记中,则可能会带来有害的副作用(例如<font color=black>...</font>)和不可避免的脆弱性(绝对没有)。特别是手动方法:

  • 邀请意外遗漏。忘记在另一个紧要周末的凌晨3:14嵌入一个工具提示吗?是的 那不会包装。希望您认真地通过所有工具提示进行测试,否则您会遇到麻烦。
  • 邀请意外碰撞与HTML语法 -值得注意的是,保留&<>字符。要避免冲突,需要手动预处理整个应用程序中的所有工具提示文本。您不能再盲目地复制和粘贴工具提示文本,因为这不再保证安全。忘记在同一通宵的代码弯折器中甚至&&amp;工具提示中的单个替换吗?是的 那不会解析。希望您认真地通过所有工具提示进行测试,否则您会遇到麻烦。
  • 无法缩放。现有的Qt应用程序通常会定义淫秽的工具提示。如果你的呢?希望您喜欢以HTML安全的方式全局搜索和替换所有工具提示文本,避免与保留的HTML字符冲突。你不会

我们已经确定手动方法是错误的方法。那么,什么是正确的方法?在这个布满虫子的世界里,甚至还有这样的事情吗?

全局事件过滤器:正确的方法

实际上,正确的方法是The Qt Company(QtC)已经修复了该错误。不完全是。已经三年多了。纯文本工具提示仍然从根本上仍然无效。

由于修复该棘手的错误似乎不可行,因此,每个Qt应用程序都可以通过安装整个应用程序范围的事件过滤器针对该应用程序在全局范围内进行操作。对于那些不熟悉Qt事件过滤器的人,嗨!我建议阅读可悲的过节摘录,该节摘自可悲的过时文本《使用Qt4进行C ++ GUI编程》的“ 事件处理”一章。考虑到普通在线文章的放射性半衰期,它的年龄出奇地好。

每个人都升级了吗?我们开工吧。

无论何时设置任何小部件的工具提示,都会在实际设置该工具提示之前立即触发该QEvent::ToolTipChange事件。同样,在基于- 单例的事件上安装事件过滤器会将应用程序中每个对象的每个事件发送到该过滤器的方法,然后再将该事件发送到其他任何地方。QApplicationqAppeventFilter()

这两个观察结果共同得出以下通用解决方案:

  1. 定义QAwesomeTooltipEventFilter库存QObject基础类的新子类。
  2. 在此子类中,将eventFilter()方法重写为:
    1. 如果当前事件是QEvent::ToolTipChange事件:
      1. 检测此事件设置的工具提示是否为:
        • 富文本(即,包含一个或多个类似HTML的富文本标签)。
        • 纯文本(即不包含此类标签)。
      2. 如果此工具提示是纯文本:
        1. 转义此工具提示中所有冲突的HTML语法(例如,通过&&amp;子字符串全局替换所有字符)。
        2. 将此工具提示嵌入最安全的,类似于HTML的富文本标记中,以确保始终减少到无用(即<qt>...</qt>)。
        3. 将此小部件的工具提示设置为该文本。
        4. 停止处理此事件。
    2. 否则,传播而不是处理该事件-确保富文本工具提示和所有其他事件保持不变。
  3. 在为您的应用程序创建单例之后,QApplication::installEventFilter()立即将此新子类的实例传递给方法。QApplication

由于Qt无条件地包装了富文本工具提示,因此以这种方式将所有纯文本全局转换为富文本工具提示可以正确地包装所有工具提示,甚至不需要一行人为干预。...也许鼓掌

一点代码,也许吗?

必要的代码取决于您的应用程序是否为:

  • C ++。在这种情况下,我建议剥夺官方bitcoinGUI的灵感。陈旧的C ++在这里超出了我的志愿者职责,因为我很懒。特别是,您要:
  • Python。在这种情况下,这是您幸运的StackOverflow日。

以下基于Python的事件过滤器假定使用PySide2 Qt绑定,因为...原因。从理论上讲,重写此筛选器以替换Qt绑定(例如PyQt5,PySide)减少为将所有PySide2子字符串换成您的首选绑定名称。

最后,我喜欢大量的reStructuredText(reST)文档-特别是对于像这样的Qt核心行为的非平凡的猴子补丁。如果不这样做,您就会知道该怎么办。

import html
from PySide2.QtCore import Qt, QEvent, QObject
from PySide2.QtWidgets import QWidget

class QAwesomeTooltipEventFilter(QObject):
    '''
    Tooltip-specific event filter dramatically improving the tooltips of all
    widgets for which this filter is installed.

    Motivation
    ----------
    **Rich text tooltips** (i.e., tooltips containing one or more HTML-like
    tags) are implicitly wrapped by Qt to the width of their parent windows and
    hence typically behave as expected.

    **Plaintext tooltips** (i.e., tooltips containing no such tags), however,
    are not. For unclear reasons, plaintext tooltips are implicitly truncated to
    the width of their parent windows. The only means of circumventing this
    obscure constraint is to manually inject newlines at the appropriate
    80-character boundaries of such tooltips -- which has the distinct
    disadvantage of failing to scale to edge-case display and device
    environments (e.g., high-DPI). Such tooltips *cannot* be guaranteed to be
    legible in the general case and hence are blatantly broken under *all* Qt
    versions to date. This is a `well-known long-standing issue <issue_>`__ for
    which no official resolution exists.

    This filter globally addresses this issue by implicitly converting *all*
    intercepted plaintext tooltips into rich text tooltips in a general-purpose
    manner, thus wrapping the former exactly like the latter. To do so, this
    filter (in order):

    #. Auto-detects whether the:

       * Current event is a :class:`QEvent.ToolTipChange` event.
       * Current widget has a **non-empty plaintext tooltip**.

    #. When these conditions are satisfied:

       #. Escapes all HTML syntax in this tooltip (e.g., converting all ``&``
          characters to ``&amp;`` substrings).
       #. Embeds this tooltip in the Qt-specific ``<qt>...</qt>`` tag, thus
          implicitly converting this plaintext tooltip into a rich text tooltip.

    .. _issue:
        https://bugreports.qt.io/browse/QTBUG-41051
    '''


    def eventFilter(self, widget: QObject, event: QEvent) -> bool:
        '''
        Tooltip-specific event filter handling the passed Qt object and event.
        '''

        # If this is a tooltip event...
        if event.type() == QEvent.ToolTipChange:
            # If the target Qt object containing this tooltip is *NOT* a widget,
            # raise a human-readable exception. While this should *NEVER* be the
            # case, edge cases are edge cases because they sometimes happen.
            if not isinstance(widget, QWidget):
                raise ValueError('QObject "{}" not a widget.'.format(widget))

            # Tooltip for this widget if any *OR* the empty string otherwise.
            tooltip = widget.toolTip()

            # If this tooltip is both non-empty and not already rich text...
            if tooltip and not Qt.mightBeRichText(tooltip):
                # Convert this plaintext tooltip into a rich text tooltip by:
                #
                #* Escaping all HTML syntax in this tooltip.
                #* Embedding this tooltip in the Qt-specific "<qt>...</qt>" tag.
                tooltip = '<qt>{}</qt>'.format(html.escape(tooltip))

                # Replace this widget's non-working plaintext tooltip with this
                # working rich text tooltip.
                widget.setToolTip(tooltip)

                # Notify the parent event handler this event has been handled.
                return True

        # Else, defer to the default superclass handling of this event.
        return super().eventFilter(widget, event)
Run Code Online (Sandbox Code Playgroud)

全局安装此事件过滤器,然后减少到以下两层:

from PySide2.QtGui import qApp
qApp.installEventFilter(QAwesomeTooltipEventFilter(qApp))
Run Code Online (Sandbox Code Playgroud)

瞧!二十行Python中的全局合理的工具提示。什么?斜眼看是二十岁。

什么是渔获?

根据您使用的确切Qt绑定,Qt.mightBeRichText()实际上可能未定义上面调用的实用程序函数(可能是由于绑定解析器问题)。如果这是您绑定的可悲情况,则最简单的解决方案是:

  • 假设所有工具提示均为纯文本,只需删除对的调用即可Qt.mightBeRichText()不聪明
  • 扫描此工具提示以查找类似HTML的标签,大概使用正则表达式试探法。聪明但超过了我的懒惰阈值

我们在这里做。