遮挡式引导界面设计

语言方向: QT C++

在你的 PTP 界面调用

cpp 复制代码
// 在你的 PTP 窗口类中添加
#include "PtpGuide.h"
PtpGuide *m_guide;

// 初始化时调用
m_guide = new PtpGuide(this);

// 添加你的按钮步骤(改成你界面的按钮名)
m_guide->addStep(ui->btn_home,    "① 请点击【回零】按钮");
m_guide->addStep(ui->btn_enable,  "② 请点击【伺服使能】");
m_guide->addStep(ui->btn_set_pos, "③ 请设置目标位置");
m_guide->addStep(ui->btn_start,   "④ 点击【启动】执行PTP运动");

// 开始按钮
void PtpWindow::on_btn_startGuide_clicked()
{
    m_guide->start();
}

PtpGuide.h

cpp 复制代码
#include <QObject>
#include <QPushButton>
#include <QMessageBox>
#include <QTimer>
#include <QLabel>
#include "MaskWidget.h"

// 步骤结构体
struct GuideStep
{
    QPushButton *targetBtn;
    QString tipMsg;
};

class PtpGuide : public QObject
{
    Q_OBJECT
public:
    explicit PtpGuide(QWidget *parentPage);
    void addStep(QPushButton *btn, const QString &msg);
    void start();
    void stop();

private slots:
    void nextStep();
    void onBtnClicked();

private:
    void showCurrentStep();
    void clearHighlight();
    void showTipBalloon();

    QWidget *m_parentPage;
    MaskWidget *m_mask;       // 半透明遮罩
    QLabel *m_tipLabel;       // 固定提示框
    QList<GuideStep> m_steps;
    int m_currentStep = -1;
    QPushButton *m_lastBtn = nullptr;
};

ptpguide.cpp

cpp 复制代码
#include "PtpGuide.h"

PtpGuide::PtpGuide(QWidget *parentPage)
    : QObject(parentPage), m_parentPage(parentPage)
{
    // 创建遮罩
    m_mask = new MaskWidget(m_parentPage);
    m_mask->setGeometry(m_parentPage->rect());
    m_mask->hide();

    // 创建提示框
    m_tipLabel = new QLabel(m_parentPage);
    m_tipLabel->setStyleSheet("background: white; color: black; padding:6px; border:1px solid gray;");
    m_tipLabel->setVisible(false);
}

// 添加步骤
void PtpGuide::addStep(QPushButton *btn, const QString &msg) {
    m_steps.append({btn, msg});
}

// 开始引导
void PtpGuide::start() {
    if (m_steps.isEmpty()) return;
    m_currentStep = 0;
    m_mask->show();
    m_mask->raise();
    showCurrentStep();
}

// 显示当前步骤:遮罩挖空 + 高亮 + 提示
void PtpGuide::showCurrentStep() {
    auto step = m_steps[m_currentStep];
    clearHighlight();

    m_lastBtn = step.targetBtn;
    m_mask->setTargetButton(m_lastBtn);

    // 按钮高亮
    m_lastBtn->setStyleSheet("border:3px solid #ff5500; background:#fff9c4;");

    // 提示框显示在按钮上方
    showTipBalloon();

    // 点击按钮 → 下一步
    connect(m_lastBtn, &QPushButton::clicked, this, &PtpGuide::onBtnClicked, Qt::UniqueConnection);
}

// 提示框
void PtpGuide::showTipBalloon() {
    auto step = m_steps[m_currentStep];
    QPoint pos = step.targetBtn->mapToParent(QPoint(0, -40));
    m_tipLabel->setText(step.tipMsg);
    m_tipLabel->move(pos);
    m_tipLabel->show();
    m_tipLabel->raise();
}

// 清除高亮
void PtpGuide::clearHighlight() {
    if (m_lastBtn) {
        m_lastBtn->setStyleSheet("");
        disconnect(m_lastBtn, nullptr, this, nullptr);
    }
}

// 按钮点击 → 延迟进入下一步
void PtpGuide::onBtnClicked() {
    QTimer::singleShot(300, this, &PtpGuide::nextStep);
}

// 下一步
void PtpGuide::nextStep() {
    m_currentStep++;
    if (m_currentStep >= m_steps.size()) {
        stop();
        QMessageBox::information(m_parentPage, "完成", "PTP操作引导已完成!");
        return;
    }
    showCurrentStep();
}

// 停止引导
void PtpGuide::stop() {
    clearHighlight();
    m_mask->hide();
    m_tipLabel->hide();
}

MaskWidget.hpp

cpp 复制代码
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>

class MaskWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MaskWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setAttribute(Qt::WA_TransparentForMouseEvents); // 遮罩不拦截鼠标
    }

    // 设置要高亮显示的按钮
    void setTargetButton(QWidget *btn) {
        m_targetBtn = btn;
        update();
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        if (!m_targetBtn) return;

        QPainter p(this);
        p.fillRect(rect(), QColor(0, 0, 0, 180)); // 半透明黑遮罩

        // 挖空:按钮区域变透明
        QRect btnRect = m_targetBtn->rect();
        QPoint globalPos = m_targetBtn->mapToGlobal(pos());
        QRect targetRect = QRect(globalPos, btnRect.size());

        p.setCompositionMode(QPainter::CompositionMode_Clear);
        p.fillRect(targetRect, Qt::transparent);
    }

private:
    QWidget *m_targetBtn = nullptr;
};
相关推荐
qq_401700411 天前
TCP 长连接、心跳包与断线自动重连设计:工业级通信的“不死鸟”架构
网络·qt·tcp/ip
dyxal2 天前
A2A 协议 v1.0 完全指南:方法名、Agent Card、三种绑定与 FastAPI 实战
开发语言·qt·fastapi
金色熊族2 天前
在Qt中使用asan检测内存泄漏(一)
linux·qt·asan
前行中的小猪2 天前
Qt 5 踩坑实录:多显示器跨屏拖拽导致窗口异常放大与 setGeometry 报错的深度解析与根治
qt·多显示器·高分辨率·多屏幕
想做小南娘,发现自己是女生喵2 天前
QT项目实战第一周(嵌入式)
开发语言·qt
誰能久伴不乏2 天前
【无标题】
c++·qt·机器人
金色熊族2 天前
在Qt中使用asan检测内存泄漏(二)--检查依赖库的内存使用
linux·qt·asan
qq_401700412 天前
Qt 组播(Multicast)实战详解
开发语言·qt
布莱克6053 天前
QtWidgets 与 QML:两大 UI 开发框架的全面对比
开发语言·c++·qt·ui·架构
qq_401700413 天前
Qt 实时大数据量存储:自己动手实现 TDMS 读写
数据库·qt