昨天我們用寫死檔案路徑方式來讀取地一張圖片。方法簡單暴力,但是顯然使用者不會滿意。
看圖軟體,當然要能隨意地打開任何一張圖吧?今天就來實現這個功能。
我們先進行一點小重構,把讀取圖片的邏輯,抽出來變成成員函數:
// 函數內容跟昨天完全一致,只是變成獨立函數
void MainWindow::loadImage(const QString &fileName)
{
QImageReader reader(fileName);
reader.setAutoTransform(true);
const QImage newImage = reader.read();
Q_ASSERT(!newImage.isNull());
m_imageLabel->setPixmap(QPixmap::fromImage(newImage));
}
這樣,只要任何時候呼叫 loadImage(path) 就可以載入圖片了
接著來實現拖放顯示圖片。第一步,呼叫setAcceptDrops(true)
告知 MainWindow 請它接收滑鼠拖拉事件。
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
m_imageLabel = new QLabel(this);
setCentralWidget(m_imageLabel);
setAcceptDrops(true); // 啟動滑鼠拖拉功能!
}
接著要覆寫兩個成員函數 dragEnterEvent() 和 dropEvent()。當有視窗上方發生任何的滑鼠拖拉行為,就會觸發這兩個函數。
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
~MainWindow();
// 增加這兩個跟滑鼠拖拉有關的函數
void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override;
...
};
mainwindow.cpp 實現滑鼠拖放的邏輯。
第一個是 dragEnterEvent(),看函數名稱大概可以猜到事件的觸發時機:滑鼠游標拖動檔案「進入視窗範圍」時觸發。我們拿它來作基本的判斷,只要拖進來的東西有包含路徑(URL)我們就放行。
dragEnterEvent() 會傳入一個事件參數 QDragEnterEvent,要表示接受檔案,需要呼叫 event->acceptProposedAction()。
void MainWindow::dragEnterEvent(QDragEnterEvent* event)
{
if (event->mimeData()->hasUrls())
{
event->acceptProposedAction();
}
}
再來實現第二個 dropEvent(),同樣的看函數名稱,事件的觸發時間點是當使用者「拖曳檔案後,放開滑鼠按鍵」時觸發。
拖拉完放開按鍵時,會傳入事件參數 QDropEvent。透過這個事件參數,我們可以獲取一個路徑清單 event->mimeData()->urls(),我們就抓取第一個物件,將URL轉換成本機檔案路徑,接著用 loadImage() 讀取圖片。
最後要接受事件,同樣呼叫 event->acceptProposedAction()。
void MainWindow::dropEvent(QDropEvent* event)
{
const QUrl url = event->mimeData()->urls().first();
const QString filePath = url.toLocalFile();
loadImage(filePath);
event->acceptProposedAction();
}
這樣子拖拉顯示功能就完成囉!試試看,把任意圖片拖放到視窗放,看看是不是能顯示圖片了呢?