您当前的位置: 首页 >  qt

Qt实战案例(53)——利用QDrag实现拖拽拼图功能

发布时间:2022-07-24 17:33:07 ,浏览量:5

目录
    • 一、项目介绍
    • 二、项目基本配置
    • 三、UI界面设置
    • 四、主程序实现
      • 4.1 main.cpp
      • 4.1 mainwindow.h头文件
      • 4.2 mainwindow.cpp源文件
      • 4.3 PiecesList类
      • 4.4 PuzzleWidget类
    • 五、效果演示
一、项目介绍

本文介绍利用QDrag类实现拖拽拼图功能。左边是打散的图,拖动到右边进行复现,此外程序还支持手动拖入原图片。

二、项目基本配置

新建一个Qt案例,项目名称为“puzzle”,基类选择“QMainWindow”,取消选中创建UI界面复选框,完成项目创建。

三、UI界面设置

UI界面如下: 无UI界面

四、主程序实现 4.1 main.cpp

源文件main.cpp中需要预先调用loadImage函数加载图像并显示界面,代码如下:

QApplication a(argc, argv); MainWindow w; w.loadImage(QStringLiteral(":/example.jpg")); w.show(); return a.exec(); 
4.1 mainwindow.h头文件

头文件中声明相应的对象和槽函数:

public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void loadImage(const QString &path); public slots: void openImage(); void setupPuzzle(); private slots: void setCompleted(); private: void setupMenus(); void setupWidgets(); QPixmap puzzleImage; PiecesList *piecesList; PuzzleWidget *puzzleWidget; 
4.2 mainwindow.cpp源文件

源文件中对函数进行定义,首先在构造函数中运行setupMenus()函数和setupWidgets()函数并设置大小尺寸和标题:

setupMenus(); setupWidgets(); setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));//设置大小策略 setWindowTitle(tr("拖拽拼图")); 

定义打开图像函数:

//打开图像(重新选择图像分割) void MainWindow::openImage() { const QString directory = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath()); QFileDialog dialog(this, tr("Open Image"), directory);//创建打开文件对话框 dialog.setFileMode(QFileDialog::ExistingFile);//设置返回存在的文件名 QStringList mimeTypeFilters; for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes()) mimeTypeFilters.append(mimeTypeName); mimeTypeFilters.sort(); //排序 dialog.setMimeTypeFilters(mimeTypeFilters); dialog.selectMimeTypeFilter("image/jpeg"); if (dialog.exec() == QDialog::Accepted) loadImage(dialog.selectedFiles().constFirst()); } 

定义加载图像函数:

// 加载图片 void MainWindow::loadImage(const QString &fileName) { QPixmap newImage; if (!newImage.load(fileName)) { QMessageBox::warning(this, tr("Open Image"), tr("The image file could not be loaded."), QMessageBox::Close); return; } puzzleImage = newImage; setupPuzzle(); } 

拼图完成后弹出完成对话框:

//拼图完成后弹出对话框 void MainWindow::setCompleted() { QMessageBox::information(this, tr("拼图完成"), tr("恭喜!您已经成功拼图 \n" "点击OK重新开始"), QMessageBox::Ok); setupPuzzle(); } 

建立拼图函数:

void MainWindow::setupPuzzle() { int size = qMin(puzzleImage.width(), puzzleImage.height());//获取图像宽度和高度的最小值 puzzleImage = puzzleImage.copy((puzzleImage.width() - size) / 2, (puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->width(), puzzleWidget->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//缩放 piecesList->clear();//清空List //切分成5*5=25张拼图 for (int y = 0; y < 5; ++y) { for (int x = 0; x < 5; ++x) { int pieceSize = puzzleWidget->pieceSize(); QPixmap pieceImage = puzzleImage.copy(x * pieceSize, y * pieceSize, pieceSize, pieceSize); piecesList->addPiece(pieceImage, QPoint(x, y)); } } for (int i = 0; i < piecesList->count(); ++i) { if (QRandomGenerator::global()->bounded(2) == 1) { QListWidgetItem *item = piecesList->takeItem(i); piecesList->insertItem(0, item); } } puzzleWidget->clear(); } 

设置菜单栏:

//设置菜单栏 void MainWindow::setupMenus() { QMenu *fileMenu = menuBar()->addMenu(tr("&文件")); QAction *openAction = fileMenu->addAction(tr("&打开..."), this, &MainWindow::openImage); openAction->setShortcuts(QKeySequence::Open); //快捷键 QAction *exitAction = fileMenu->addAction(tr("&退出"), qApp, &QCoreApplication::quit); exitAction->setShortcuts(QKeySequence::Quit); //快捷键 QMenu *gameMenu = menuBar()->addMenu(tr("&游戏")); gameMenu->addAction(tr("&重启"), this, &MainWindow::setupPuzzle); } 

设置界面布局:

//设置界面布局 void MainWindow::setupWidgets() { QFrame *frame = new QFrame; QHBoxLayout *frameLayout = new QHBoxLayout(frame);//水平布局 puzzleWidget = new PuzzleWidget(400);//新建PuzzleWidget对象,设置图像尺寸为400 piecesList = new PiecesList(puzzleWidget->pieceSize(), this); connect(puzzleWidget, &PuzzleWidget::puzzleCompleted, this, &MainWindow::setCompleted, Qt::QueuedConnection); frameLayout->addWidget(piecesList); frameLayout->addWidget(puzzleWidget); setCentralWidget(frame);//中心部件 } 
4.3 PiecesList类

新建PiecesList类,并继承自QListWidget: 在这里插入图片描述

4.4 PuzzleWidget类

新建PuzzleWidget类,继承自QWidget: 在这里插入图片描述 它实现了以下几个方法。

void dragEnterEvent(QDragEnterEvent *event) override; void dragLeaveEvent(QDragLeaveEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override; void dropEvent(QDropEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; 

Drag执行的流程是: Drag是从drag->exec()开始的,此时将开启进入一个新的事件循环,然后在拖动的过程中会在下面三个事件中交替: 在这里插入图片描述 其中DragEnter是有拖动进入该Widget时触发的,对应的DragLeave则是拖动离开时触发的,而DragMove就是鼠标拖动的时候触发的。

最后当鼠标释放的时候将触发dragEvent,此时将决定拖拽的结果。

回头看一下Drag的触发,和大多数系统一样,一个Drag可能是从控件外触发的,即将外部的数据拖入,也可以是从控件内部触发,即手动生成一个QDrag对象。

拖动的机制: 其实拖动就是将一处的数据移动或者复制到另外一处,在QT中拖动所承载的数据使用QMimeData表示的,它可以用来表示许多Mime Type的集合。一个Mime Type即有format和data两部分组成,format即指示了如何解析对应的data。更详细的定义可以参考:http://en.wikipedia.org/wiki/MIME。

五、效果演示

完整效果如下: 初始界面: 在这里插入图片描述 拼图完成后界面: 在这里插入图片描述

如果没有看懂的话,完整代码可以参考:https://download.csdn.net/download/didi_ya/86249377

ok,以上便是本文的全部内容了,如果对你有所帮助,记得点个赞哟~

关注
打赏
1688896170
查看更多评论

暂无认证

  • 5浏览

    0关注

    115984博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0453s