0

我正在寻找一种方法来检测 Qt 小部件的 ToolTip 在按下特定组合键时是否可见。如果是,我想将工具提示的文本复制到剪贴板。

具体来说,我有一个包含缩写字符串的 QListView,它设置为(通过关联模型的 Qt::ToolTipRole)以在鼠标悬停在相应列表项上时显示相应列表项的完整字符串。我正在寻找的行为是,如果用户在工具提示可见时按下 CTRL-C(由 QShortcut 检测到),则工具提示文本将复制到剪贴板。

我最初的想法是使用 QListView 小部件的 children() 方法来查看其中是否有工具提示预设:

// Inisde the slot connected to QShortcut::activated...
auto children = _ui -> myListView -> children();
QString selectionText;
for (const auto & child : children)
{
    if (qobject_cast<QToolTip *>(child))
    {
        selectionText = qobject_cast<QToolTip *>(child) -> text();
        break;
    }
}

...但这失败了,因为事实证明 QToolTip 不是从 QObject 继承的。

我还考虑过在 ListView 的主事件处理程序中筛选 QEvent::QToolTip 事件,虽然我可能可以让它工作,但它似乎过于低级;我需要使用屏幕坐标来确定列表中的哪个项目被悬停并查找小部件的超时以检查在触发 QShortcut 时工具提示是否再次消失。如果没有更简单的方法,我会感到失望。

有没有我看不到的明显前进方向?

4

2 回答 2

1

可能有几种可能的解决方案,但恐怕没有一个是简单的。我要做的是使用调用工具提示实际小部件的实现细节QTipLabel。请参阅https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qtooltip.cpp.html#QTipLabel它继承自,QLabel因此您可以轻松地从中获取文本。

恐怕以下解决方案只是一个野蛮的黑客攻击。我没有测试过它,但它应该可以工作。

  1. 我将为您的视图覆盖数据模型,特别是覆盖方法data(),该data()方法将调用原始模型类的方法,但缓存使用 调用此方法时返回的最后一个值role == Qt::ToolTipRole
  2. 然后你需要捕捉你感兴趣的快捷方式。捕捉后,你会得到所有qApp->topLevelWidgets() 的 https://doc.qt.io/qt-5/qapplication.html#topLevelWidgets`并通过它们并检查它们是否有类名等于QTipLabel(use QMetaObject::className()) 并且是可见的,即isVisible() == true.
  3. 如果你得到这个可见的QTipLabel小部件(你通过 持有它QWidget*),qobject_castQLabel*(你不能将它转换为因为QTipLabel你无权访问QTipLabel类的定义,因为它在私有 Qt 源文件中)并使用QLabel::text(). 如果文本与您在步骤 1 中存储的文本相同,那么是的,这就是您要查找的文本,您可以将其复制到剪贴板或做任何您想做的事情。

恶心,不是吗?但这是我能想到的最简单的。

PS:我相信第 1 步也可以通过捕捉QEvent::QToolTip您的视图来实现,然后做一些魔术来获取文本,但我认为覆盖data()模型可能会更容易一些。

PPS:一个明显的缺点是 QtQTipLabel将来可以重命名类。但我不会担心。这不会发生,因为他们不再更改 QtWidgets 模块。如果发生这种情况,那么您只需在代码中重命名该类。没问题。

PPPS:另一个潜在的极端情况是,其他一些小部件(您不想使用该快捷方式捕获其工具提示)实际上与列表视图中的任何项目(您确实想要捕获)具有相同的工具提示文本。然后,如果您为列表项显示工具提示,则将鼠标移到该其他小部件并悬停以显示其工具提示(但您不想捕获它),然后按该快捷方式...但我猜实际上这不会是你的情况。我怀疑会有这种不太可能的工具提示冲突。

于 2022-02-09T14:21:47.087 回答
0

感谢@VK,这是有效的:

auto candidates = qApp->topLevelWidgets();
QString selectionText;
for (const auto & candidate : candidates)
{
    if (strcmp(candidate->metaObject()->className(), "QTipLabel") == 0)
    {
        QLabel * label = qobject_cast<QLabel *>(candidate);
        if (label->isVisible())
        {
            selectionText = label -> text();
            break;
        }
    }
}
if (!selectionText.isEmpty())
    QGuiApplication::clipboard() -> setText(selectionText);
于 2022-02-10T11:14:32.397 回答