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;
   }
}
相关推荐
TPBoreas3 小时前
Jenkins 改完端口号启动不起来了
java·开发语言
TE-茶叶蛋3 小时前
Vuerouter 的底层实现原理
开发语言·javascript·ecmascript
云闲不收4 小时前
设计模式原则
开发语言
秋名RG4 小时前
深入解析建造者模式(Builder Pattern)——以Java实现复杂对象构建的艺术
java·开发语言·建造者模式
技术求索者4 小时前
c++学习
开发语言·c++·学习
山猪打不过家猪5 小时前
(二)毛子整洁架构(CQRS/Dapper/领域事件处理器/垂直切片)
开发语言·.net
方博士AI机器人7 小时前
Python 3.x 内置装饰器 (4) - @dataclass
开发语言·python
weixin_376934637 小时前
JDK Version Manager (JVMS)
java·开发语言
Logintern097 小时前
【每天学习一点点】使用Python的pathlib模块分割文件路径
开发语言·python·学习
cykaw25908 小时前
QT 文件选择对话框 QFileDialog
开发语言·qt