赞
踩
因为 QToolTip 自定义样式不大方便,而且半透明也没法设置,所以需要自定义。
Qt 中的顶层 QWidget 好像默认是不支持透明样式的,可以设置:
- setWindowFlags(Qt::FramelessWindowHint);
- setAttribute(Qt::WA_TranslucentBackground, true); //无边框才有效
这样顶层窗口是透明了,但是样式表又没效果了。虽然可以用 QStyleOption 获取到样式表设置的颜色等信息,然后在 paintEvent 中绘制,但是图片我不知道怎么获取 。索性就嵌套了两层 widget ,再给里层的 widget 设置样式,里层也能直接用 QLabel 显示文本。
显示和隐藏我是过滤的 QEvent::Enter 和 QEvent::Leave 来进行操作:
- switch (event->type()) {
- case QEvent::Enter:
- //showTip(QCursor::pos());
- showTip(targetWidget);
- break;
- case QEvent::Leave:
- hideTip();
- break;
- default:
- break;
- }
目前的实现是相对一个 widget 固定位置 show 的,如锚定一个按钮的位置,但没有处理鼠标移动事件,只处理 enter 和 leave。
弹出的时候因为我是先计算的位置再 show ,可能大小还没计算出来,所以在 resizeEvent 中重新调用了计算位置的函数。
最初我是外层用 QWidget,但是设置 parent 后不能独立窗口显示,不设置 parent 设置样式表和 delete 又麻烦,所以改成了 QDialog,然后内部放一个 QLabel 显示文字。
参考 Qt 源码:E:\Qt\qt-everywhere-src-5.15.0\qtbase\src\widgets\kernel\qtooltip.h
实现效果
代码链接
github 链接(CuteToolTip 类):https://github.com/gongjianbo/QtWidgetsComponent
主要代码
- #pragma once
- #include <QDialog>
- #include <QLabel>
- #include <QBasicTimer>
- #include "CuteComponentExport.h"
-
- /**
- * @brief 最简易的 ToolTip 提示框
- * @author 龚建波
- * @date 2020-6-7
- * @details
- * 外部为 QDialog,设置 parent 后也能独立窗口显示
- * 内部套一个 QLabel 显示文字
- */
- class Cute_API CuteToolTip : public QDialog
- {
- Q_OBJECT
- // 默认显示为 point 的左上角,通过属性设置偏移,左-右+,上-下+,同屏幕坐标系规则
- // qss 右移 1px: qproperty-xOffset:"1";
- Q_PROPERTY(int xOffset READ getXOffset WRITE setXOffset NOTIFY xOffsetChanged)
- // qss 上移 1px: qproperty-yOffset:"-1";
- Q_PROPERTY(int yOffset READ getYOffset WRITE setYOffset NOTIFY yOffsetChanged)
- Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged)
- Q_PROPERTY(Qt::Alignment alignment READ getAlignment WRITE setAlignment NOTIFY alignmentChanged)
- public:
- explicit CuteToolTip(const QString text = QString(), QWidget *parent = nullptr);
- ~CuteToolTip();
-
- // x 轴偏移
- int getXOffset() const;
- void setXOffset(int offset);
- // y 轴偏移
- int getYOffset() const;
- void setYOffset(int offset);
-
- // 文本
- QString getText() const;
- void setText(const QString &text);
- // 对齐方式
- Qt::Alignment getAlignment() const;
- void setAlignment(Qt::Alignment alignment);
-
- // 设置锚定窗口,鼠标放上去时显示 tooltip
- void anchorTarget(QWidget *target);
- // 获取内层 label 对象
- const QLabel *label() const;
- // 显示 tip 在 widget 的左上角
- void showTip(const QWidget *obj);
- // 显示 tip 在点的左上角
- void showTip(const QPoint &rightBottom);
- // 隐藏 tip
- void hideTip();
-
- protected:
- // 过滤锚定窗口的 enter 和 leave 事件
- bool eventFilter(QObject *target, QEvent *event) override;
- void timerEvent(QTimerEvent *event) override;
- void resizeEvent(QResizeEvent *event) override;
-
- signals:
- void xOffsetChanged();
- void yOffsetChanged();
- void textChanged();
- void alignmentChanged();
-
- private:
- // 内部套一个 QLabel 显示文字
- QLabel *contentLabel{ nullptr };
- // 默认显示为 point 的左上角,通过属性设置偏移
- // 左-右+,上-下+,同屏幕坐标系规则
- int xOffset{ 0 };
- int yOffset{ 0 };
-
- // 锚定的窗口
- QWidget *targetWidget{ nullptr };
- QPoint targetPoint;
- // show 和 hide 延迟
- QBasicTimer showTimer;
- QBasicTimer hideTimer;
- };
- #include "CuteToolTip.h"
- #include <QGuiApplication>
- #include <QScreen>
- #include <QEvent>
- #include <QTimerEvent>
- #include <QResizeEvent>
- #include <QHBoxLayout>
- //#include <QDebug>
-
- CuteToolTip::CuteToolTip(const QString text, QWidget *parent)
- : QDialog{parent}
- , contentLabel{new QLabel(this)}
- {
- // 把内层 label 添加到透明 dialog
- QHBoxLayout *layout = new QHBoxLayout(this);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setSpacing(0);
- layout->addWidget(contentLabel);
-
- contentLabel->setAlignment(Qt::AlignCenter);
- contentLabel->setText(text);
-
- // 把 dialog 设置为透明,样式表设置给 label
- setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);
- setAttribute(Qt::WA_TranslucentBackground, true);
- // 默认 hide
- setVisible(false);
- // qDebug() << __FUNCTION__;
- }
-
- CuteToolTip::~CuteToolTip()
- {
- // qDebug() << __FUNCTION__;
- }
-
- int CuteToolTip::getXOffset() const
- {
- return xOffset;
- }
-
- void CuteToolTip::setXOffset(int offset)
- {
- if (xOffset != offset){
- xOffset = offset;
- // 没有动态样式的处理,可自行添加
- // style()->unpolish(this);
- // style()->polish(this);
- emit xOffsetChanged();
- }
- }
-
- int CuteToolTip::getYOffset() const
- {
- return yOffset;
- }
-
- void CuteToolTip::setYOffset(int offset)
- {
- if (yOffset != offset){
- yOffset = offset;
- emit yOffsetChanged();
- }
- }
-
- QString CuteToolTip::getText() const
- {
- return contentLabel->text();
- }
-
- void CuteToolTip::setText(const QString &text)
- {
- if (getText() != text) {
- contentLabel->setText(text);
- emit textChanged();
- }
- }
-
- Qt::Alignment CuteToolTip::getAlignment() const
- {
- return contentLabel->alignment();
- }
-
- void CuteToolTip::setAlignment(Qt::Alignment alignment)
- {
- if (getAlignment() != alignment) {
- contentLabel->setAlignment(alignment);
- emit alignmentChanged();
- }
- }
-
- void CuteToolTip::anchorTarget(QWidget *target)
- {
- if (!target) return;
- if (target != targetWidget) {
- if (targetWidget) {
- targetWidget->removeEventFilter(this);
- }
- targetWidget = target;
- targetWidget->installEventFilter(this);
- targetWidget->setMouseTracking(true);
- }
- }
-
- const QLabel *CuteToolTip::label() const
- {
- return contentLabel;
- }
-
- void CuteToolTip::showTip(const QWidget *obj)
- {
- if (!obj) return;
- showTip(obj->mapToGlobal(QPoint(0, 0)));
- }
-
- void CuteToolTip::showTip(const QPoint &rightBottom)
- {
- targetPoint = rightBottom;
- // move(rightBottom.x() - width() + xOffset,
- // rightBottom.y() - height() + yOffset);
- // 直接用size + point得到的位置可能显示不全,这里计算下
-
- int rect_left = rightBottom.x() - width() + xOffset;
- int rect_top = rightBottom.y() - height() + yOffset;
- // 根据当前所在屏幕尺寸计算,左上角不超过范围
- // 因为锚定的左上角显示,右下角暂不考虑
- // 老版本用 QDesktopWidget
- // QDesktopWidget *desktop = QApplication::desktop();
- // QRect desk_rect=desktop->screenGeometry(targetWidget);
- // Qt5.11 QDesktopWidget 部分接口被废弃,Qt6 该类被移除
- // 新版本用 QScreen
- // 直接用 widget 的 screen() 获取的是整个 window 所在 screen,而不是组件的
- // 跨屏时在哪个屏幕占的区域最大,就以该屏幕作为组件的所属 screen
- QScreen *screen = nullptr;
- if (targetWidget) {
- screen = QGuiApplication::screenAt(targetWidget->mapToGlobal(targetWidget->rect().center()));
- }
- if (screen) {
- QRect desk_rect = screen->geometry();
- if(rect_left < desk_rect.x())
- rect_left = desk_rect.x();
- if(rect_top < desk_rect.y())
- rect_top = desk_rect.y();
- } else {
- if (rect_left < 0)
- rect_left = 0;
- if (rect_top < 0)
- rect_top = 0;
- }
-
- move(rect_left, rect_top);
- if (!showTimer.isActive())
- showTimer.start(200, this);
- }
-
- void CuteToolTip::hideTip()
- {
- if (!hideTimer.isActive())
- hideTimer.start(300, this);
- }
-
- bool CuteToolTip::eventFilter(QObject *target, QEvent *event)
- {
- if (target == targetWidget) {
- switch (event->type()) {
- case QEvent::Enter:
- // showTip(QCursor::pos());
- showTip(targetWidget);
- break;
- case QEvent::Leave:
- hideTip();
- break;
- default:
- break;
- }
- }
- return QWidget::eventFilter(target, event);
- }
-
- void CuteToolTip::timerEvent(QTimerEvent *event)
- {
- if (event->timerId() == showTimer.timerId()) {
- showTimer.stop();
- // hideTimer.stop();
- if (!hideTimer.isActive() && isHidden()) {
- show();
- }
- } else if (event->timerId() == hideTimer.timerId()) {
- showTimer.stop();
- hideTimer.stop();
- if (!isHidden()) {
- hide();
- }
- } else {
- QWidget::timerEvent(event);
- }
- }
-
- void CuteToolTip::resizeEvent(QResizeEvent *event)
- {
- // 初次 show 的时候可能 size 可能还没计算好
- showTip(targetPoint);
- QWidget::resizeEvent(event);
- }
使用
- void ToolTipDemo::initToolTip()
- {
- CuteToolTip *tip_a = new CuteToolTip("Tip A", ui->btnToolTipA);
- // 通过 objectName 区分样式表设置
- tip_a->setObjectName("tipA");
- tip_a->anchorTarget(ui->btnToolTipA);
- // 样式表设置为固定尺寸 tip
- tip_a->setStyleSheet(R"(
- .CuteToolTip#tipA{
- min-width:100px;
- max-width:100px;
- min-height:30px;
- max-height:30px;
- }
- .CuteToolTip#tipA QLabel{
- color:white;
- border:1px solid white;
- padding:0;
- border-radius:5px;
- background-color:rgba(250,170,0,150);
- }
- )");
-
- CuteToolTip *tip_b = new CuteToolTip("Tip B", ui->btnToolTipB);
- tip_b->setObjectName("tipB");
- tip_b->anchorTarget(ui->btnToolTipB);
- // 自适应的尺寸
- tip_b->setStyleSheet(R"(
- .CuteToolTip#tipB{
- qproperty-xOffset:"20";
- qproperty-yOffset:"3";
- }
- .CuteToolTip#tipB QLabel{
- padding:10px 30px;
- color:white;
- border:1px solid white;
- background-color:rgb(20,50,90);
- }
- )");
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。