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;
   }
}
相关推荐
choumin9 小时前
创建型模式——工厂方法模式
c++·设计模式·工厂方法模式·创建型模式
云小逸9 小时前
【SVN 详细使用指南:从入门到团队协作】
c++·svn
互联网中的一颗神经元10 小时前
小白python入门 - 39. 采集流水线小项目
开发语言·python
Wang's Blog11 小时前
Go-Zero 项目开发22:用户群聊功能的实现与完善
开发语言·golang
a11177611 小时前
坦克大战3D Three.js 3D (开源项目)
开发语言·javascript·3d
Wang's Blog13 小时前
Go-Zero项目开发24: 基于Bitmap实现群聊消息已读未读
开发语言·后端·golang
龚建波14 小时前
《QDebug 2026年6月》
qt
ziguo112214 小时前
深入浅出 C/C++ 数据类型:从入门到踩坑
linux·c语言·c++·windows·visual studio
白色冰激凌15 小时前
[SECS/GEM研究] (三)SECS-I 串口上消息怎么分块和重传
c++·secs/gem
光头闪亮亮15 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go