Qt利用QDrag實現拖拽拼圖功能詳解
一、項目介紹
本文介紹利用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。
五、效果演示
完整效果如下:
初始界面:
拼圖完成後界面:
到此這篇關於Qt利用QDrag實現拖拽拼圖功能詳解的文章就介紹到這瞭,更多相關Qt QDrag拖拽拼圖內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!