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;
   }
}
相关推荐
Java小白笔记9 小时前
Java 实现阿里云 OSS 文件上传链路:普通上传、秒传、分片与断点续传
java·开发语言·数据库·spring·阿里云
传奇开心果编程9 小时前
【Rust入门知识点学与练】第9课:Vec 动态数组
开发语言·学习·rust
卢锡荣9 小时前
单芯掌控多口互联|乐得瑞 LDR6020 PD3.1 多通道 Type‑C 控制 SOC 芯片
c语言·开发语言
2333!!!!!9 小时前
rocket新手一些常见问题
java·开发语言
yume_sibai9 小时前
02-Rust 所有权与借用深入解析(底层原理 + 借用检查器 + 生命周期 + 内部可变性)
开发语言·后端·rust
xxwxx__9 小时前
深入理解 C++ STL:stack、queue 与 deque 从使用到底层实现全解析
开发语言·c++·算法
Highcharts.js9 小时前
甘特图纵向任务、横向时间显示图表可视化开发|Highcharts甘特图示例
开发语言·前端·javascript·可视化·甘特图·数据可视化·highcharts
wuminyu9 小时前
JVM锁膨胀与Futex源码解析
java·linux·c语言·jvm·c++
郝学胜-神的一滴9 小时前
C++11 工程级应用 08:Lambda表达式与Tuple元组
开发语言·jvm·c++·python·程序人生·开源
吴声子夜歌9 小时前
ApacheCommons——commons-lang3(Java 基础语言增强)(二)
java·开发语言·apache