Qt 拖拽 动态 垃圾箱

来源:互联网 发布:九阴绝学金身升级数据 编辑:程序博客网 时间:2024/05/14 20:10

前些天看了Qt的拖拽,觉得Qt的拖拽还是蛮灵活;但widgets在移动端类似的app应用场景下,确实显得有一些笨拙;但同时它功能强大,灵活性非常高。

我在这里实现的是一个类似于android手机卸载软件时的动态垃圾箱。先看下效果是这样的。


支持自动缩放,自适应啰。



被拖动的目标显然用QListWidget来存放最方便,这也是拖拽的一个典型应用。垃圾箱的动画使用了QPropertyAnimation,其它的就是拖拽的事件监听了;下面请看代码

#include "widget.h"#include <QApplication>#include <QListWidget>#include <QPropertyAnimation>#include <QVBoxLayout>#include <QPushButton>#include <QBitmap>#include <QPainter>#include <QResizeEvent>#include <QDebug>Widget::Widget(QWidget *parent)    : QWidget(parent){    QVBoxLayout *lay = new QVBoxLayout(this);    listWidget = new QListWidget;    listWidget->setViewMode(QListWidget::IconMode); //设置显示方式    listWidget->addItem(new QListWidgetItem(QIcon(":/img/test.png"),QStringLiteral("test"))); //放一个item到ListWidget    listWidget->addItem(new QListWidgetItem(QIcon(":/img/trash.png"),QStringLiteral("trash")));//放一个item到ListWidget    listWidget->installEventFilter(this); //为ListWidget添加事件监听,用于检测item项是否被拖动    lay->addWidget(listWidget); //主布局    reRect = new QLabel(this);            //顶上垃圾箱背景label    reRect->setAutoFillBackground(true);    QPalette pal = reRect->palette();    pal.setBrush(QPalette::Background,Qt::lightGray); //设置背景色    reRect->setPalette(pal);    QPixmap pix(":/img/trash.png");    reRect->resize(width(),pix.height() + 20);  //重设label尺寸    reRect->setMinimumHeight(pix.height() + 20);     reLabel = new QLabel;                //垃圾桶    reLabel->resize(pix.size());        //重调垃圾桶label尺寸    reLabel->setPixmap(pix);    reLabel->setMask(pix.mask());    reLabel->setAcceptDrops(true);     //使能够接受拖拽的落下    reLabel->installEventFilter(this); //添加事件监听    QHBoxLayout *hlay = new QHBoxLayout(reRect);    hlay->addWidget(reLabel,0,Qt::AlignCenter); //在背景label中居中    ani = new QPropertyAnimation(reRect, "geometry"); //新建动画,绑定属性为背景label的geometry    ani->setEasingCurve(QEasingCurve::InCurve);       //设置动画插值方式    ani->setDuration(150);                            //动画持续时间    connect(ani,&QPropertyAnimation::finished,[&]{ani->setDirection(QAbstractAnimation::Direction(!ani->direction()));}); //改变方向}void Widget::resizeEvent(QResizeEvent *event){    reRect->resize(event->size().width(),reRect->height()); //当窗口发生变化时,重调背景label尺寸    if(initFlag){      //当第一次初始化时,移动到窗体外面        initFlag = false;        reRect->move(reRect->x(),-reRect->height());    }    ani->setStartValue(QRect(reRect->x(),-reRect->height(),reRect->width(),reRect->height())); //设置动画起点值    ani->setEndValue(reRect->rect());   //设置动画终点值    return QWidget::resizeEvent(event);}Widget::~Widget(){}bool Widget::eventFilter(QObject *watched, QEvent *event){    if(reLabel = qobject_cast<QLabel*>(watched)){        if(event->type() == QEvent::DragEnter){            QDragEnterEvent *drageEnterE{nullptr};            try{                drageEnterE = dynamic_cast<QDragEnterEvent*>(event);            }catch(std::bad_cast &e){                qDebug() << e.what();            }            if(drageEnterE){                trashPainted = false;                drageEnterE->acceptProposedAction(); //当拖拽事件进入时,启用接收拖拽            }            return true;        }else if(event->type() == QEvent::Drop){            QDropEvent *dropE{nullptr};            try{                dropE = dynamic_cast<QDropEvent*>(event);            }catch(std::bad_cast &e){                qDebug() << e.what();            }            if(dropE){                listWidget->takeItem(listWidget->row(listWidget->currentItem())); //当在垃圾箱落下时,从ListWidget中删除当前项,并恢复垃圾箱颜色                QPixmap *pix = const_cast<QPixmap*>(reLabel->pixmap());                *pix = QPixmap(":/img/trash.png");                reLabel->repaint();            }            return true;        }else if(event->type() == QEvent::DragMove){            QDragMoveEvent *mvEvent{nullptr};            try{                mvEvent = dynamic_cast<QDragMoveEvent*>(event);            }catch(std::bad_cast &e){                qDebug() << e.what();            }            if(mvEvent && !trashPainted){   //当item项在垃圾箱上漂荡时,改变垃圾箱颜色                QPixmap *pix = const_cast<QPixmap*>(reLabel->pixmap());                QPainter p(pix);                p.initFrom(pix);                p.fillRect(pix->rect(),QColor(200,0,0,50));                reLabel->repaint();                trashPainted = !trashPainted;            }            return true;        }else if(event->type() == QEvent::DragLeave){            QDragLeaveEvent *leEvent{nullptr};            try{                leEvent = dynamic_cast<QDragLeaveEvent*>(event);            }catch(std::bad_cast &e){                qDebug() << e.what();            }            if(leEvent){                QPixmap *pix = const_cast<QPixmap*>(reLabel->pixmap()); //当拖拽事件离开时,恢复垃圾箱颜色                *pix = QPixmap(":/img/trash.png");                reLabel->repaint();            }            return true;        }    }else if(listWidget == qobject_cast<QListWidget*>(watched)){        QChildEvent *childEvent{nullptr};        switch (event->type()) {        case QEvent::ChildAdded:            try{                childEvent = dynamic_cast<QChildEvent*>(event);            }catch(std::bad_cast &e){                qDebug() << e.what();            }            if(childEvent){  //当item项被视为拖动时,启动动画                ani->start();            }            break;        case QEvent::ChildRemoved:            try{                childEvent = dynamic_cast<QChildEvent*>(event);            }catch(std::bad_cast &e){                qDebug() << e.what();            }            if(childEvent){  //当item拖动结束时,启动动画                ani->start();            }            break;        }    }    return QWidget::eventFilter(watched,event);}

我做得比较简单,如果完美一点,应该在最后那段代码中;当item被拖动时应该判断动画执行方向,如果此时动画还是离开窗体中,就应该先停止动画,然后改变方向,再启动动画;当拖动结束时也是一样的。不过我这里设置的动画持续时间比较短,这个现象问题不大。

需要源码可到处下载