1. 程式人生 > >Qt專案實戰2:圖片檢視器QImageViewer

Qt專案實戰2:圖片檢視器QImageViewer

在博文Qt學習筆記2:QMainWindow和QWidget的區別中介紹了使用空的Qt專案建立帶有選單欄、工具欄的介面。
這裡,使用一個簡單的圖片檢視器專案,來熟悉一下Qt的圖片顯示和基本操作。
該專案實現的主要功能:

  • 實現圖片的開啟、關閉、居中顯示;
  • 實現圖片上一張/下一張切換;
  • 實現圖片的放大、縮小操作
  • 實現圖片的左旋、右旋操作

需要用的Qt類:

QFileDialog  QImage  QPixmap  QFileInfo

使用空的Qt專案建立帶有選單欄和工具欄的介面的操作參考博文Qt學習筆記1:建立一個QT的空專案

頁面佈局

根據自己的實際需求新增選單欄和工具欄,參考如下圖:

1

工具欄圖示依次是:開啟圖片、關閉圖片、上一張、下一張、左旋、右旋、放大、縮小

此專案算是一個小demo,主要是熟悉圖片處理的相關的操作,基礎類和操作熟悉之後可以加入複雜的功能。

實現圖片的開啟、關閉

檔案開啟和顯示的步驟:
(1)使用QFileDislog函式選擇一個圖片檔案,獲取到檔案的路徑名;
(2)使用QImage類載入檔案,生成image物件;
(3)使用QLabel類的setPixmap函式將圖片顯示在介面上。

參考程式碼如下:

void QImageViewer::openActionTriggered
(void) { filename = QFileDialog::getOpenFileName(this, tr("Select image:"), "D:\\Documents\\Pictures", tr("Images (*.png *.bmp *.jpg *.gif)")); if (filename.isEmpty()) { return ; } QImage image; if (!image.load(filename)) { QMessageBox::information(this, tr("Error"
), tr("Open file error")); return ; } QPixmap pixmap = QPixmap::fromImage(image); imageSize = pixmap.size(); imageLabel->setPixmap(pixmap); imageLabel->resize(imageSize); //qDebug() << "filname: " << filename; setWindowTitle(QFileInfo(filename).fileName() + tr(" - imageViewer")); }

圖片關閉時,只需將label清空即可:

void QImageViewer::closeActionTriggered(void)
{
    imageLabel->clear();
    imageLabel->resize(QSize(200, 100));
    setWindowTitle(tr("imageViewer"));
}

圖片開啟、關閉的函式,作為QAction的槽函式觸發即可:

    connect(openAction, SIGNAL(triggered(bool)), this, SLOT(openActionTriggered()));
    connect(closeAction, SIGNAL(triggered(bool)), this, SLOT(closeActionTriggered()));

提示:在圖片開啟時可以將介面名改為檔名+標題,關閉時去掉檔名,方便使用者使用。

實現圖片居中顯示、頁面自動調整

通過上述操作,已經可以建立一個label,並將圖片顯示在label中。

但是會出現各種問題,例如:label在resize時部分尺寸超出頁面的大小顯示不全、圖片不能居中顯示等。

需要做以下操作來解決上述問題:

  • 使用QLabel類的setPixmap函式將圖片顯示在介面上;
  • 建立一個QScrollArea部件,將label載入到scrollarea中;
  • 設定scrollarea部件為中心對齊,無邊框;
  • 設定頁面佈局方式為格點佈局,並將scrollarea部件增加到0,0點上。

參考程式碼:

void QImageShow::setImageShowWidget(void)
{
    /* label show image */
    imageLabel = new QLabel();

    QScrollArea *imageScrollArea = new QScrollArea();
    imageScrollArea->setAlignment(Qt::AlignCenter);
    imageScrollArea->setFrameShape(QFrame::NoFrame);
    imageScrollArea->setWidget(imageLabel);

    QGridLayout *mainLayout = new QGridLayout();
    mainLayout->addWidget(imageScrollArea, 0, 0);
    centralWidget->setLayout(mainLayout);
}

當開啟一張圖片時,自動居中對齊;當圖片大小超過中心視窗尺寸時,scrollarea部件出現滑動條,顯示配合放大、縮小功能,顯示效果更好。
效果如下圖所示:

2

實現上一張/下一張切換

在開啟檔案同時,獲取到當前目錄的檔案列表,儲存到檔案資訊連結串列中。
當需要對開啟的檔案上、下切換時,只需對當前連結串列的下表進行輪詢並獲取圖片顯示即可。

void QImageViewer::getImgInfoList(QFileInfoList &imgInfoList)
{
    imgInfoList.clear();

    QDir dir = QFileInfo(filename).absolutePath();
    QFileInfoList infoList = dir.entryInfoList(QDir::Files);
    //qDebug() << "GET:" << infoList.count() << dir;

    QFileInfo info;
    for (int i = 0; i < infoList.count(); i++) {
        info = infoList.at(i);
        //qDebug() << i << info.absolutePath();
        QString suffix = info.suffix();

        if (suffix == "jpg" || suffix == "bmp" || suffix == "png") {
            imgInfoList.append(info);
            //qDebug() << "getImgInfoList:" << i << info.absolutePath() << info.suffix();
        }
    }

    QFileInfo curImageInfo = QFileInfo(filename);
    for (int j = 0; j < imgInfoList.count(); j++) {
        info = imgInfoList.at(j);
        if (info.fileName() == curImageInfo.fileName()) {
            index = j;
            //qDebug() << "curImage index:" << index;
        }
    }
}

在選單欄和工具欄增加上一張/下一張按鈕,實現QAction行為觸發。

實現步驟:
(1)使用QFileInfoList連結串列儲存下已經開啟的檔案所在路徑下所有的圖片檔案的資訊;
(2)記錄下當前檔案的下表,上一張/下一張時間觸發時,對下標進行增減;
(3)獲取到檔案路徑和檔名;
(4)重新構造image物件,載入圖片檔案並顯示。

參考程式碼:

void QImageViewer::lastActionTriggered(void)
{
    //getImgInfoList(imgInfoList);

    index = index - 1;
    int count = imgInfoList.count();
    //qDebug() << "left count: " << count << "index: " << index;
    if (index < 0) {
        index = count - 1;
    }

    filename.clear();
    filename.append(path);
    filename += "/";
    filename += imgInfoList.at(index).fileName();
    //qDebug() << "filname: " << filename;

    QImage image;
    if (!image.load(filename)) {
        QMessageBox::information(this, tr("Error"), tr("Open file error"));
        return ;
    }

    QPixmap pixmap = QPixmap::fromImage(image);
    imageSize = pixmap.size();

    imageLabel->setPixmap(pixmap);
    imageLabel->resize(imageSize);

    setWindowTitle(QFileInfo(filename).fileName() + tr(" - imageViewer"));
}

void QImageViewer::nextActionTriggered(void)
{
    //getImgInfoList(imgInfoList);

    index = index + 1;
    int count = imgInfoList.count();
    //qDebug() << "right count: " << count << "index: " << index;
    if (index == count) {
        index = 0;
    }

    filename.clear();
    filename.append(path);
    filename += "/";
    filename += imgInfoList.at(index).fileName();
    //qDebug() << "filname: " << filename;

    QImage image;
    if (!image.load(filename)) {
        QMessageBox::information(this, tr("Error"), tr("Open file error"));
        return ;
    }

    QPixmap pixmap = QPixmap::fromImage(image);
    imageSize = pixmap.size();

    imageLabel->setPixmap(pixmap);
    imageLabel->resize(imageSize);

    setWindowTitle(QFileInfo(filename).fileName() + tr(" - imageViewer"));
}

圖片的左旋、右旋操作

圖片的旋轉使用QImage類的transformed行為來實現,使用成員變數儲存下當前圖片的旋轉角度,每次觸發旋轉操作,將旋轉角度以90度間隔增減。

實現步驟:
(1)通過當前圖片檔名靜態載入image;
(2)將成員變數旋轉角度,以90度間隔增、減;
(3)通過QImage類的transformed行為修改載入的圖片角度;
(4)顯示修改後的圖片,並重置圖片尺寸等;

參考程式碼:

void QImageViewer::toLeftActionTriggered(void)
{
    QImage imgRotate;
    QMatrix matrix;
    QPixmap pixmap;
    QImage image;

    imageAngle += 3;
    imageAngle = imageAngle % 4;
    qDebug() << "angle:%d" << imageAngle;
    matrix.rotate(imageAngle * 90);

    image.load(filename);
    imgRotate = image.transformed(matrix);
    pixmap = QPixmap::fromImage(imgRotate);
    imageSize = pixmap.size();

    imageLabel->resize(imgRotate.size());
    imageLabel->setPixmap(pixmap);
}

void QImageViewer::toRightActionTriggered(void)
{
    QImage imgRotate;
    QMatrix matrix;
    QPixmap pixmap;
    QImage image;

    imageAngle += 1;
    imageAngle = imageAngle % 4;
    //qDebug() << "angle:%d" << imageAngle;
    matrix.rotate(imageAngle * 90);

    image.load(filename);
    imgRotate = image.transformed(matrix);
    pixmap = QPixmap::fromImage(imgRotate);
    imageSize = pixmap.size();

    imageLabel->resize(imgRotate.size());
    imageLabel->setPixmap(pixmap);
}

圖片的放大、縮小操作

圖片的放大、縮小操作通過QImage類的scaled行為實現。可以重置image的尺寸,返回新的image物件。

這裡增加一個功能:支援圖片旋轉之後進行放大、縮小操作。只需對放大、縮小後新的image物件再進行旋轉操作即可。

實現步驟:
(1)通過當前圖片檔名靜態載入image;
(2)修改成員變數圖片尺寸,設定放大倍數為1.2,縮小倍數為0.8,儲存新的尺寸;
(3)通過QImage類的transformed行為修改載入的圖片角度;
(5)顯示修改後的圖片,並重置圖片尺寸等;

參考程式碼:

void QImageViewer::toEnlargeActionTriggered(void)
{
    QImage imgScaled;
    QPixmap pixmap;
    QImage image;
    QImage imgRotate;
    QMatrix matrix;

    image.load(filename);
    matrix.rotate(imageAngle * 90);
    imgRotate = image.transformed(matrix);

    imgScaled = imgRotate.scaled(imageSize.width() * 1.2,
                             imageSize.height() * 1.2,
                             Qt::KeepAspectRatio);

    pixmap = QPixmap::fromImage(imgScaled);
    imageSize = pixmap.size();
    //qDebug() << "width:%d, height:%d" << imageSize.width() << imageSize.height();

    imageLabel->setPixmap(pixmap);
    imageLabel->resize(imageSize);
}

void QImageViewer::toLessenActionTriggered(void)
{
    QImage imgScaled;
    QPixmap pixmap;
    QImage image;
    QImage imgRotate;
    QMatrix matrix;

    image.load(filename);
    matrix.rotate(imageAngle * 90);
    imgRotate = image.transformed(matrix);

    imgScaled = imgRotate.scaled(imageSize.width() * 0.8,
                             imageSize.height() * 0.8,
                             Qt::KeepAspectRatio);

    pixmap = QPixmap::fromImage(imgScaled);
    imageSize = pixmap.size();
    //qDebug() << "width:%d, height:%d" << imageSize.width() << imageSize.height();

    imageLabel->setPixmap(pixmap);
    imageLabel->resize(imageSize);
}

需要注意的地方

  • 圖片關閉、上一張、下一張操作是在圖片開啟成功之後才能操作,所以誤點按鈕導致程式崩潰,需要加使能操作。

  • 此處圖片物件的建立沒有使用new操作,理由是需要手動delete比較麻煩;直接使用區域性變數,編譯器會自動釋放資源。

  • 此處使用空的Qt模板建立,不使用系統的ui檔案,需要手動初始化選單欄、工具欄和中心視窗等。

原始碼下載連結:https://github.com/gitorup/QImageViewer