Qt实现引导界面UITour

介绍

最近做了一款键鼠自动化,想第一次安装打开后搞一个引导界面,找了好多资料没啥参考,偶然发现qt有引导界面如下图。

在这里插入图片描述

Qt整挺好,但是未找到源码,真的不想手撸,(源码找到了但是Qt整起来太复杂,没法拿来直接用,还是得撸)地地址

下图是仿照qt实现,除了qt明亮边缘的渐变其余部分均已实现,箭头完美复刻,支持上下左右。
在这里插入图片描述
废话少说

直接上代码

#ifndef TOURGUIDE_H
#define TOURGUIDE_H

#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QPalette>
#include <QBrush>


enum WSAD_POS {
    TOP_POS,
    DOWN_PPOS,
    LEFT_POS,
    RIGHT_POS
};
class TourGuide : public QWidget
{
    Q_OBJECT
public:
    explicit TourGuide(QWidget* w, QWidget *parent = 0);

    void onAddWidget(QWidget* w, QString title, QStringList contentList, int pos);
signals:

public slots:

protected:
    void paintEvent(QPaintEvent *event);
    void mousePressEvent(QMouseEvent *event);
private:
    //绘制箭头 WSAD绘制方向
    void drawArrows(QPainter& painter, QPoint pos, QRect rect, WSAD_POS WSAD);
private:
    QList<QWidget*> m_ListWidget;
    QList<QString> m_ListWidgetStr;
    QList<QStringList> m_ListWidgetStrList;
    QList<WSAD_POS> m_ListWidgetPos;

    int m_index = 0;

    QWidget* m_MainWindows;
    QLine targetLine;
};

#endif // TOURGUIDE_H

#include "tourguide.h"

#include <QDebug>
TourGuide::TourGuide(QWidget *w, QWidget *parent) : QWidget(parent)
{
    m_MainWindows = w;
}

void TourGuide::onAddWidget(QWidget *w, QString title, QStringList contentList, int pos)
{
    m_ListWidget << w;
    m_ListWidgetStr << title;
    m_ListWidgetStrList << contentList;

    m_ListWidgetPos << WSAD_POS(pos);
}

void TourGuide::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    if (m_index < 0 || m_index >= m_ListWidget.size())
        return;

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    QWidget *currentWidget = m_ListWidget[m_index];
    if (!currentWidget)
        return;


    // 获取QWidget在主窗体的位置
    QPoint guidePos = currentWidget->mapTo(m_MainWindows, QPoint(0, 0));
    QRect rect(guidePos.x(), guidePos.y(), currentWidget->width(), currentWidget->height());
    //循环如果包含该ui就不绘制
    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor(0, 0, 0, 100));

    // 当前widget的大小
    int fullWidth = this->width();
    int fullHeight = this->height();

    // 计算四周矩形区域
    QRect topRect(0, 0, fullWidth, rect.y());
    QRect bottomRect(0, rect.y() + rect.height(), fullWidth, fullHeight - (rect.y() + rect.height()));
    QRect leftRect(0, rect.y(), rect.x(), rect.height());
    QRect rightRect(rect.x() + rect.width(), rect.y(), fullWidth - (rect.x() + rect.width()), rect.height());

    // 设置笔刷
    painter.setBrush(QColor(0, 0, 0, 100));

    // 绘制四周矩形 把ui的位置进行空出来,绘制它的四个区域,仅支持规则ui,这样就不支持奇形怪状
    painter.drawRect(topRect);
    painter.drawRect(bottomRect);
    painter.drawRect(leftRect);
    painter.drawRect(rightRect);

    painter.setBrush(QColor(0, 0, 0, 0));

    QPen pen(Qt::green);

    //圈出来
    pen.setWidth(1);
    painter.setPen(pen);
    painter.drawRect(rect);

    drawArrows(painter, guidePos, currentWidget->rect(), m_ListWidgetPos.at(m_index));

    // 绘制矩形框和箭头
    // 绘制文字
    painter.setPen(Qt::white); // 设置文字颜色为白色
    QFont font = painter.font(); // 获取当前字体设置
    font.setPointSize(18); // 设置字体大小
    font.setBold(true); // 设置为粗体
    painter.setFont(font); // 应用设置后的字体
    // 获取文本的宽度和高度
    QRectF textRect = painter.boundingRect(QRectF(), Qt::AlignCenter, m_ListWidgetStr.at(m_index));

    // 计算文字应该绘制的位置,使其居中在窗口中央
    qreal x = (this->width() - textRect.width()) / 2;
    qreal y = (this->height() - textRect.height()) / 2;
    // 绘制标题文字
    painter.drawText(QPointF(x, y), m_ListWidgetStr.at(m_index));
    QStringList list = m_ListWidgetStrList.at(m_index);


    // 绘制子文字
    for (int i = 0 ; i < list.size(); ++i) {
        textRect = painter.boundingRect(QRectF(), Qt::AlignCenter, list.at(i));
        x = (this->width() - textRect.width()) / 2;
        y = (this->height() - textRect.height()) / 2 + ((i+1) * 40);
        font.setPointSize(12);
        font.setBold(false);
        painter.setFont(font); // 应用设置后的字体
        // 绘制标题文字
        painter.drawText(QPointF(x, y), list.at(i));
    }
}

void TourGuide::mousePressEvent(QMouseEvent *event)
{
    if (event->type() == QMouseEvent::MouseButtonPress) {
        this->update();
        qDebug() << m_index;
        if (m_index < m_ListWidget.size()) {
            m_index++;
        }
        else {
            this->close();
        }
    }
}

void TourGuide::drawArrows(QPainter &painter, QPoint pos, QRect rect, WSAD_POS WSAD)
{
    QPoint f1Start;
    QPoint f1Stop;
    QPoint f2Start;
    QPoint f2Stop;
    QPoint f3Start;
    QPoint f3Stop;
    if (WSAD == TOP_POS) {
        // 绘制箭头
        f1Start = QPoint(pos.x() + (rect.width() / 2), pos.y() - 5);
        f1Stop = QPoint(pos.x() + (rect.width() / 2) - 6, pos.y() - 12);
        //绘制两边的线
        f2Start = QPoint(pos.x() + (rect.width() / 2), pos.y() - 5);
        f2Stop = QPoint(pos.x() + (rect.width() / 2) + 6, pos.y() - 12);

        //绘制中间的线
        f3Start = QPoint(pos.x() + (rect.width() / 2), pos.y() - 5);
        f3Stop = QPoint(pos.x() + (rect.width() / 2), pos.y() - 20);
    }
    else if (WSAD == DOWN_PPOS) {
        // 绘制箭头
        f1Start = QPoint(pos.x() + (rect.width() / 2), pos.y() + rect.height() + 5);
        f1Stop = QPoint(pos.x() + (rect.width() / 2) - 6, pos.y() + rect.height() + 12);
        //绘制两边的线
        f2Start = QPoint(pos.x() + (rect.width() / 2), pos.y() + rect.height() + 5);
        f2Stop = QPoint(pos.x() + (rect.width() / 2) + 6, pos.y() + rect.height() + 12);

        //绘制中间的线
        f3Start = QPoint(pos.x() + (rect.width() / 2), pos.y() + rect.height() + 5);
        f3Stop = QPoint(pos.x() + (rect.width() / 2), pos.y() + rect.height() + 20);
    }
    else if (WSAD == LEFT_POS) {
        // 绘制箭头
        f1Start = QPoint(pos.x() - 5, pos.y() + (rect.height() / 2));
        f1Stop = QPoint(pos.x() - 12, pos.y() + 5);
        //绘制两边的线
        f2Start = QPoint(pos.x() - 5, pos.y() + (rect.height() / 2));
        f2Stop = QPoint(pos.x() - 12, pos.y() + (rect.height() / 2) + 6);

        //绘制中间的线
        f3Start = QPoint(pos.x() - 5, pos.y() + rect.height() / 2);
        f3Stop = QPoint(pos.x() - 20, pos.y() + rect.height() / 2);
    }
    else if (WSAD == RIGHT_POS) {
        // 绘制箭头
        f1Start = QPoint(pos.x() + rect.width() + 5, pos.y() + (rect.height() / 2));
        f1Stop = QPoint(pos.x() + rect.width() + 12, pos.y() + 5);
        //绘制两边的线
        f2Start = QPoint(pos.x() + rect.width() + 5, pos.y() + (rect.height() / 2));
        f2Stop = QPoint(pos.x() + rect.width() + 12, pos.y() + (rect.height() / 2) + 6);

        //绘制中间的线
        f3Start = QPoint(pos.x() + rect.width() + 5, pos.y() + rect.height() / 2);
        f3Stop = QPoint(pos.x() + rect.width() + 20, pos.y() + rect.height() / 2);
    }

    QPen pen(Qt::green);
    pen.setWidth(2);
    painter.setPen(pen);
    painter.drawLine(f1Start, f1Stop);
    painter.drawLine(f2Start, f2Stop);
    painter.drawLine(f3Start, f3Stop);
}


调用方式

    m_T = new TourGuide(this, this);
    m_T->onAddWidget(ui->pushButton, "这是第1个按钮", QStringList() << "他是第1个", 0);
    m_T->onAddWidget(ui->pushButton_2, "这是第2个按钮", QStringList() << "他是第2个", 1);
    m_T->onAddWidget(ui->pushButton_3, "这是第3个按钮", QStringList() << "他是第3个", 2);
    m_T->onAddWidget(ui->pushButton_4, "这是第4个按钮", QStringList() << "他是第4个", 3);
    m_T->setFixedSize(this->size());

1.优化半透明色绘制,由于前期采用双for循环绘制,导致刷新效率降低,现采用计算四周区域进行绘制,但是这样会带来仅支持规则区域,正方形,长方形,如果是不规则ui还得用for循环来判断,如果想实现那就要再写个算法来优化,例如如果是圆形那就计算出它的四边区域位置然后将他空出一个正方形然后进行for循环修补。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/56345.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python系统学习1-2

目录 一、硬件 二、软件&#xff1a;程序文档 三、基础知识 四、python执行过程 五、Pycharm使用技巧 一、硬件 计算机五大部件&#xff1a;运算器&#xff0c;存储器&#xff0c;控制器、输入设备&#xff0c;输出设备。 运算器和控制器 集成在CPU中。 存储&#xff1a…

Qt Creator 11 开放源码集成开发环境新增集成终端和 GitHub Copilot 支持

导读Qt 项目今天发布了 Qt Creator 11&#xff0c;这是一款开源、免费、跨平台 IDE&#xff08;集成开发环境&#xff09;软件的最新稳定版本&#xff0c;适用于 GNU/Linux、macOS 和 Windows 平台。 Qt Creator 11 的亮点包括支持标签、多外壳、颜色和字体的集成终端模拟器&am…

hcip——BGP实验

要求 1.搭建toop 2.地址规划 路由器AS接口地址R11 loop0:1.1.1.1 24 loop1 : 192.168.1.1 24 g0/0/0 12.0.0.1 24 R22 64512 g0/0/0: 12.0.0.2 24 g/0/01: 172.16.0.2 19 g0/0/2: 172.16.96.2 19 R32 64512g0/0/0: 172.16.0.3 19 g0/0/1:1…

在使用Python爬虫时遇到解析错误解决办法汇总

在进行Python爬虫任务时&#xff0c;遇到解析错误是常见的问题之一。解析错误可能是由于网页结构变化、编码问题、XPath选择器错误等原因导致的。为了帮助您解决这个问题&#xff0c;本文将提供一些实用的解决办法&#xff0c;并给出相关的代码示例&#xff0c;希望对您的爬虫任…

实现Feed流的三种模式:拉模式、推模式和推拉结合模式

在互联网产品中&#xff0c;Feed流是一种常见的功能&#xff0c;它可以帮助我们实时获取我们关注的用户的最新动态。Feed流的实现有多种模式&#xff0c;包括拉模式、推模式和推拉结合模式。在本文中&#xff0c;我们将详细介绍这三种模式&#xff0c;并通过Java代码示例来实现…

Centos7 安装man中文版手册

查找man中文安装包&#xff1a; yum search man-pages 安装man-pages-zh-CN.noarch: yum install -y man-pages-zh-CN.noarch

05|Oracle学习(UNIQUE约束)

1. UNIQUE约束介绍 也叫&#xff1a;唯一键约束&#xff0c;用于限定数据表中字段值的唯一性。 1.1 UNIQUE和primary key区别&#xff1a; 主键/联合主键每张表中只有一个。UNIQUE约束可以在一张表中&#xff0c;多个字段中存在。例如&#xff1a;学生的电话、身份证号都是…

091.粉刷房子

一、题目 剑指 Offer II 091. 粉刷房子 - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public:int minCost(vector<vector<int>>& costs) {int row costs.size();int col costs[0].size();if (row 1)return min(min(costs[0][0], cos…

Mybatis ,Mybatis-plus列表多字段排序,包含sql以及warpper

根据 mybatis 根据多字段排序已经wrapper 根据多字段排序 首先根据咱们返回前端的数据列来规划好排序字段 如下&#xff1a; 这里的字段为返回VO的字段,要转换成数据库字段然后加入到排序中 示例&#xff0c;穿了 surname,cerRank 多字段,然后是倒序 false 首先创建好映射&am…

Python元编程-装饰器介绍、使用

目录 一、Python元编程装饰器介绍 二、装饰器使用 1. 实现认证和授权功能 2.实现缓存功能 3.实现日志输出功能 三、附录 1. logging.basicConfig介绍 2. 精确到毫秒&#xff0c;打印时间 方法一&#xff1a;使用datetime 方法二&#xff1a;使用time 一、Python元编程…

【Git】git reflog git log

前言 日常开发过程中&#xff0c;我们经常会遇到要进行版本回退的情况&#xff0c;这时候需要使用git reflog和git reset 命令 git reflog 常用命令&#xff1a; 1、git reflog -n 查看多少条 2、git reflog show origin 查看远程历史变动 git log 什么都不加默认显示当前分…

Python实现GA遗传算法优化循环神经网络回归模型(LSTM回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;最早是由美国的 John holland于20世…

代码随想录算法训练营之JAVA|第十八天| 235. 二叉搜索树的最近公共祖先

今天是第 天刷leetcode&#xff0c;立个flag&#xff0c;打卡60天&#xff0c;如果做不到&#xff0c;完成一件评论区点赞最高的挑战。 算法挑战链接 235. 二叉搜索树的最近公共祖先https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/descriptio…

springboot自定义错误消息

为了提供自定义错误消息提示&#xff0c;springboot在resources目录下&#xff0c;有一个文件ValidationMessages.properties 用于存储 验证错误的消息提示&#xff1a; 比如&#xff1a; 这样一个ValidationMessage.properties username.notempty用户名不能为空 username.len…

互联网宠物医院系统开发:数字化时代下宠物医疗的革新之路

随着人们对宠物关爱意识的提高&#xff0c;宠物医疗服务的需求也日益增加。传统的宠物医院存在排队等待、预约难、信息不透明等问题&#xff0c;给宠物主人带来了诸多不便。而互联网宠物医院系统的开发&#xff0c;则可以带来许多便利和好处。下面将介绍互联网宠物医院系统开发…

前端生成图片验证码怎么做?

##题记&#xff1a;我们实现一个功能首先想一下我们需要做哪些工作&#xff0c;比如我们需要生成一个随机的图片验证码&#xff0c;我们需要一个就是点击事件获取验证码&#xff0c;通过接口我们去获取图片路径进行渲染就行&#xff0c;这里边还要牵扯一件事情就是获取一个随机…

Git笔记--Ubuntu上传本地项目到github

目录 1--基本配置 2--本地上传 1--基本配置 ① 创建ssh-key cd ~/.sshssh-keygen -t rsa -C "邮箱地址"② 查看并关联ssh-key gedit id_rsa.pub 复制内容&#xff0c;在 GitHub 中依次点击 Settings -> SSH and GPG keys -> New SSH key&#xff0c;将 id…

gateway过滤器没生效,特殊原因

看这边文章的前提&#xff0c;你要会gateway&#xff0c;知道过滤器怎么配置&#xff1f; 直接来看过滤器&#xff0c;局部过滤器 再来看配置 请求路径 http://127.0.0.1:8080/appframework/services/catalog/catalogSpecials.json?pageindex1&pagesize10&pkidd98…

【微服务】springboot整合redis哨兵集群使用详解

目录 一、前言 二、环境准备 三、安装redis 3.1 前置准备 3.1.1 下载安装包 3.1.2 准备依赖环境 3.1.3 上传并解压包 3.2 执行安装 四、搭建redis主从集群 4.1 环境准备 4.2 搭建过程 4.2.1 创建实例文件目录 4.2.2 修改redis.conf配置文件 4.2.3 拷贝配置文件 4…

微信小程序页面传值为对象[Object Object]详解

微信小程序页面传值为对象[Object Object]详解 1、先将传递的对象转化为JSON字符串拼接到url上2、在接受对象页面进行转译3、打印结果 1、先将传递的对象转化为JSON字符串拼接到url上 // info为对象 let stationInfo JSON.stringify(info) uni.navigateTo({url: /pages/statio…