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;
   }
}
相关推荐
Alfred young28 分钟前
CS144 Lab Checkpoint 0: networking warm up
c++·网络协议
weixin_3077791339 分钟前
Python使用SFTP批量上传和下载一个目录下的所有文件
服务器·开发语言·python
JuicyActiveGilbert1 小时前
【C++设计模式】第五篇:原型模式(Prototype)
c++·设计模式·原型模式
幸运小圣1 小时前
模板字符串【ES6】
开发语言·javascript·es6
我的电脑会说烫1 小时前
线程池项目优化
c++
多多*2 小时前
谈谈单例模式中通过Htools包的SpringUtil.getBean获取Bean的好处
java·开发语言·windows·单例模式·面试·log4j
想你依然心痛2 小时前
侯捷 C++ 课程学习笔记:深入理解智能指针
c++·笔记·学习
Python大数据分析@2 小时前
使用DeepSeek + Python开发AI思维导图应用,非常强!
开发语言·python·ai
Erik_LinX2 小时前
算法日记33:14届蓝桥C++B冶炼金属(二分答案)
开发语言·c++·算法
我是大咖2 小时前
c语言笔记 野指针
c语言·开发语言·笔记