Qt C++ 开发 动态上下页按钮实现

项目开发,想实现动态的显示按钮,考虑使用QStackedWidget做两个页面去切换。

首先,我们使用Qt ui 画出两个QStackedWidget的两个页面


要实现切换,我们只需要调用stackedWidget->setCurrentIndex(index)就行。

那么如何自动调用呢?

这时候,我们想到网页的正常操作。当鼠标在某个区悬浮超过固定时间时,将按钮显示出来,也就是切换页面。

这里我们遇到了个坑, Qt为了缩减资源消耗,只在鼠标按下才触发mouseMoveEvent!

切记修改MouseTracking属性,我们修改了整个ui的MouseTracking属性发现没有用???

查资料,需要将所有QWidget子节点全部赋值!

cpp 复制代码
void setMouseTrackingRecursively(QWidget* widget) {
    if (widget == nullptr)
        return;
    widget->setMouseTracking(true);
    const QObjectList& children = widget->children();
    for (QObject* child : children) {
        if (child->isWidgetType()) {
            setMouseTrackingRecursively(qobject_cast<QWidget*>(child));
        }
    }
}

实现完成,发现还行,但是缺少点灵魂,动画太直接了。

好的,加动画属性:#include <QPropertyAnimation>

这玩意太多功能了,后期单独在写。

直接上代码:

endListDialog.h

cpp 复制代码
#ifndef ENDLISTDIALOG_H
#define ENDLISTDIALOG_H

#include <QDialog>
#include <QDebug>
namespace Ui {
class endListDialog;
}

class endListDialog : public QDialog
{
    Q_OBJECT

public:
    explicit endListDialog(QWidget *parent = nullptr);
    ~endListDialog();

private slots:
    void onHoverTimeout();
protected:
    void mouseMoveEvent(QMouseEvent *event);
    void switchPage(int index);
private:
    Ui::endListDialog *ui;
    bool isHovering;
    QTimer *timer;
};

#endif // ENDLISTDIALOG_H

endListDialog.cpp

cpp 复制代码
#include "endlistdialog.h"
#include "ui_endlistdialog.h"
#include <QTimer>
#include <QMouseEvent>
#include <QMessageBox>
#include <QPropertyAnimation>
bool bshow=false;

//鼠标事件mouseMoveEvent必须按下才响应 为了实现将页面所有QWidget setMouseTracking属性赋值true
void setMouseTrackingRecursively(QWidget* widget) {
    if (widget == nullptr)
        return;
    widget->setMouseTracking(true);
    const QObjectList& children = widget->children();
    for (QObject* child : children) {
        if (child->isWidgetType()) {
            setMouseTrackingRecursively(qobject_cast<QWidget*>(child));
        }
    }
}

//同理QWidget 透明设置
void setwindowOpacityRecursively(QWidget* widget) {
    if (widget == nullptr)
        return;
    widget->setMouseTracking(true);
    const QObjectList& children = widget->children();
    for (QObject* child : children) {
        if (child->isWidgetType()) {
            setwindowOpacityRecursively(qobject_cast<QWidget*>(child));
        }
    }
}

/****************************/
//切换页面实现
//入参 index 页面 (这里偷懒直接写了固定的实现)
//输出 
/****************************/
void endListDialog::switchPage(int index)
{
	//我的ui QStackedWidget对象是stackedWidget_18,换成自己的
    QWidget *currentWidget = ui->stackedWidget_18->currentWidget();
    QWidget *nextWidget = ui->stackedWidget_18->widget(index);
    // 创建动画
    // 创建缩小动画
   QPropertyAnimation *fadeOutAnimation = new QPropertyAnimation(currentWidget, "geometry");
   fadeOutAnimation->setDuration(200);
   QRect originalGeometry = currentWidget->geometry();
   QRect targetGeometry;
  if(index==1)
  { //展示第二页时 将第一页缩小一点 
     targetGeometry = QRect(originalGeometry.x() +20,
                                    originalGeometry.y() ,
                                    originalGeometry.width()-40,
                                   originalGeometry.height());
  }
  else{
  //展示第一页时 将第二页放大一点 
      targetGeometry = QRect(originalGeometry.x() -20,
                                     originalGeometry.y() ,
                                     originalGeometry.width()+40,
                                    originalGeometry.height());
   }

   fadeOutAnimation->setStartValue(originalGeometry);
   fadeOutAnimation->setEndValue(targetGeometry);

    QPropertyAnimation *fadeInAnimation = new QPropertyAnimation(nextWidget, "windowOpacity");
    fadeInAnimation->setDuration(600);
    fadeInAnimation->setStartValue(0.0);
    fadeInAnimation->setEndValue(1.0);

    // 连接动画完成信号
    connect(fadeOutAnimation, &QPropertyAnimation::finished, this, [this, index]() {
        ui->stackedWidget_18->setCurrentIndex(index);
    });

    // 启动动画
    fadeOutAnimation->start();
    fadeInAnimation->start();
}

endListDialog::endListDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::endListDialog)
{
    ui->setupUi(this);
    isHovering = false;
    timer = new QTimer();
    timer->setInterval(200); // 设置为 600 m秒
    connect(timer, &QTimer::timeout, this, &endListDialog::onHoverTimeout);

    setMouseTrackingRecursively(ui->widget);
    setwindowOpacityRecursively(ui->widget);
}

endListDialog::~endListDialog()
{
    delete ui;
}

//mouseMoveEvent的重写 ,千万记住setMouseTracking属性赋值true
//不然你只能按住才能触发 Qt为了缩减资源消耗默认赋值false
void endListDialog::mouseMoveEvent(QMouseEvent *event) {
    // 检查鼠标是否在 stackedWidget 内
    if (ui->stackedWidget_18->underMouse()) {
        // 鼠标在 stackedWidget 内部
        qDebug("Mouse is inside the stackedWidget");
        if (!isHovering) { // 仅在未悬浮时启动计时器
            isHovering = true;
            bshow=false;
            timer->start();
        }
    } else {
        // 鼠标不在 stackedWidget 内部
        qDebug("Mouse is outside the stackedWidget");
        if (isHovering) { // 仅在悬浮时停止计时器
           isHovering = false;
           timer->stop();
           switchPage(0);
       }
    }
     // 调用基类的 mouseMoveEvent
    QDialog::mouseMoveEvent(event);
}


void endListDialog::onHoverTimeout() {
    // 在这里执行悬浮超过3秒后的操作
    // 例如,显示提示信息
   // QMessageBox::information(this, "提示", "鼠标悬浮超过3秒!");
   if(!bshow)
   {
        switchPage(1);
        bshow = true;
   }
}
相关推荐
强化学习与机器人控制仿真4 分钟前
ROS & ROS2 机器人深度相机激光雷达多传感器标定工具箱入门教程(一)
开发语言·人工智能·stm32·深度学习·机器人·自动驾驶
Hello.Reader14 分钟前
快速启动 Rust + WebAssembly 项目
开发语言·rust·wasm
秋书一叶16 分钟前
Java工具类——实体类列表写入excel
java·开发语言·excel
愚润求学17 分钟前
【专题刷题】双指针(三):两数之和,三数之和,四数之和
c++·笔记·leetcode·刷题
汤姆_51121 分钟前
【c语言】深入理解指针2
c语言·开发语言
愚润求学34 分钟前
【C++】map和set
开发语言·c++·笔记
末央&39 分钟前
【C++】priority_queue的底层封装和实现
开发语言·c++
Better Rose1 小时前
【2025“华中杯”大学生数学建模挑战赛】C题:就业状态分析与预测 详细解题思路
c语言·开发语言·数学建模
网络安全研发随想1 小时前
C语言核心结构+难点精讲+工程技巧
c语言·开发语言·算法
superior tigre1 小时前
C++学习:六个月从基础到就业——面向对象编程:虚函数与抽象类
开发语言·c++·学习