天天看點

Qt項目實戰2:圖檔檢視器QImageViewer

在博文Qt學習筆記2:QMainWindow和QWidget的差別中介紹了使用空的Qt項目建立帶有菜單欄、工具欄的界面。

這裡,使用一個簡單的圖檔檢視器項目,來熟悉一下Qt的圖檔顯示和基本操作。

該項目實作的主要功能:

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

需要用的Qt類:

QFileDialog  QImage  QPixmap  QFileInfo

使用空的Qt項目建立帶有菜單欄和工具欄的界面的操作參考博文Qt學習筆記1:建立一個QT的空項目

頁面布局

根據自己的實際需求添加菜單欄和工具欄,參考如下圖:

Qt項目實戰2:圖檔檢視器QImageViewer

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

此項目算是一個小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(, ));
    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, , );
    centralWidget->setLayout(mainLayout);
}
           

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

效果如下圖所示:

Qt項目實戰2:圖檔檢視器QImageViewer

實作上一張/下一張切換

在打開檔案同時,擷取到目前目錄的檔案清單,儲存到檔案資訊連結清單中。

當需要對打開的檔案上、下切換時,隻需對目前連結清單的下表進行輪詢并擷取圖檔顯示即可。

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 = ; 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 = ; 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 - ;
    int count = imgInfoList.count();
    //qDebug() << "left count: " << count << "index: " << index;
    if (index < ) {
        index = count - ;
    }

    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 + ;
    int count = imgInfoList.count();
    //qDebug() << "right count: " << count << "index: " << index;
    if (index == count) {
        index = ;
    }

    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 += ;
    imageAngle = imageAngle % ;
    qDebug() << "angle:%d" << imageAngle;
    matrix.rotate(imageAngle * );

    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 += ;
    imageAngle = imageAngle % ;
    //qDebug() << "angle:%d" << imageAngle;
    matrix.rotate(imageAngle * );

    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 * );
    imgRotate = image.transformed(matrix);

    imgScaled = imgRotate.scaled(imageSize.width() * ,
                             imageSize.height() * ,
                             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 * );
    imgRotate = image.transformed(matrix);

    imgScaled = imgRotate.scaled(imageSize.width() * ,
                             imageSize.height() * ,
                             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

繼續閱讀