显示控件概览
图片浏览示例
第一行是一个标签控件,objectName 为 labelShow,文本内容清空,因为是用来显示图片用的。
主界面第二行的控件是四个普通按钮
第一个按钮文本是 "打开图片",objectName 为 pushButtonOpenPic;
第二个按钮文本是 "打开动态图",objectName 为 pushButtonOpenMov;
第三个按钮文本是 "播放",objectName 为 pushButtonStart;
第四个按钮文本是 "停止",objectName 为 pushButtonStop。
水平滑动条,objectName 为 horizontalSlider。这个水平滑动条适用于显示动态图播放进度的
main.cpp
#include "Qt_Show.h" #include <QtWidgets/QApplication> #include <QBitmap> int main(int argc, char *argv[]) { QApplication a(argc, argv); Qt_Show w; QPixmap pixmap("images/timg2.jpg"); // 读取图片 QPalette palette; palette.setBrush(w.backgroundRole(), QBrush(pixmap)); // 将图片设置在指定窗口 w.setPalette(palette); //w.setMask(pixmap.mask()); //可以将图片中透明部分显示为透明的 w.setAutoFillBackground(true); // 自动充满 w.show(); return a.exec(); }
窗口头文件
#pragma once #include <QtWidgets/QMainWindow> #include "ui_Qt_Show.h" #include <QPixmap> //像素图 #include <QMovie> //动态图 #include <QImageReader> //可以打开图片或者查看支持的图片格式 class Qt_Show : public QMainWindow { Q_OBJECT public: Qt_Show(QWidget *parent = Q_NULLPTR); ~Qt_Show(); public slots: //接收出错的信号 void RecvPlayError(QImageReader::ImageReaderError error); //接收播放时帧号变化 void RecvFrameNumber(int frameNumber); private slots: void on_pushButtonOpenPic_clicked(); void on_pushButtonOpenMov_clicked(); void on_pushButtonStart_clicked(); void on_pushButtonStop_clicked(); private: Ui::Qt_ShowClass ui; //像素图指针 QPixmap *m_pPixMap; //动态图指针 QMovie *m_pMovie; //是否为动态图 bool m_bIsMovie; //动态图是否在播放中,如果在播放中,那么循环播放 bool m_bIsPlaying; //清除函数,在打开新图之前,清空旧的 打开新图之前,清理旧的像素图、动态图对象,并重置两个标志位变量。 void ClearOldShow(); };
窗体实体
#include "Qt_Show.h" #include <QDebug> #include <QFileDialog> //打开文件对话框 #include <QScrollArea> //为标签添加滚动区域 #include <QMessageBox> //消息框 Qt_Show::Qt_Show(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); //初始化成员变量 m_pPixMap = NULL; m_pMovie = NULL; m_bIsMovie = false; m_bIsPlaying = false; //获取标签矩形 QRect rcLabel = ui.labelShow->geometry(); //为标签添加滚动区域,方便浏览大图 QScrollArea *pSA = new QScrollArea(this); //该对象交给主窗体自动管理,不用手动删除 //把标签填充到滚动区域里 pSA->setWidget(ui.labelShow); //设置滚动区域占据矩形 pSA->setGeometry(rcLabel); //打印支持的图片格式 qDebug() << QImageReader::supportedImageFormats(); //打印支持的动态图格式 qDebug() << QMovie::supportedFormats(); } Qt_Show::~Qt_Show() { //手动清空 ClearOldShow(); //原有的代码 // delete ui; } void Qt_Show::ClearOldShow() { //清空标签内容 ui.labelShow->clear(); //像素图不空就删除 if (m_pPixMap != NULL) { //删除像素图 delete m_pPixMap; m_pPixMap = NULL; } //如果短片不为空,就删除 if (m_pMovie != NULL) { //如果正在播放则停止 if (m_bIsPlaying) { m_pMovie->stop(); } //删除动态图 delete m_pMovie; m_pMovie = NULL; } //标志位重置 m_bIsMovie = false; m_bIsPlaying = false; } void Qt_Show::on_pushButtonOpenPic_clicked() { QString strFileName; //文件名 strFileName = QFileDialog::getOpenFileName(this, tr("打开静态图片"), "", "Pictures (*.bmp *.jpg *.jpeg *.png *.xpm);;All files(*)"); if (strFileName.isEmpty()) { //文件名为空,返回 return; } //清空旧的图片或短片 ClearOldShow(); //打印文件名 qDebug() << strFileName; //新建像素图 m_pPixMap = new QPixmap(); //加载 if (m_pPixMap->load(strFileName)) { //加载成功 //设置给标签 ui.labelShow->setPixmap(*m_pPixMap); //设置标签的新大小,与像素图一样大 ui.labelShow->setGeometry(m_pPixMap->rect()); //设置 bool 状态 m_bIsMovie = false; //不是动态图 m_bIsPlaying = false; //不是动态图播放 } else { //加载失败,删除图片对象,返回 delete m_pPixMap; m_pPixMap = NULL; //提示失败 QMessageBox::critical(this, tr("打开失败"), tr("打开图片失败,文件名为: %1").arg(strFileName)); } } void Qt_Show::on_pushButtonOpenMov_clicked() { QString strFileName; //文件名 strFileName = QFileDialog::getOpenFileName(this, tr("打开动态图片"), "", "Movies (*.gif *.mng);;All files(*)"); if (strFileName.isEmpty()) { //文件名为空,返回 return; } //清除旧的图片或短片 ClearOldShow(); //打印文件名 qDebug() << strFileName; //新建动态图 m_pMovie = new QMovie(strFileName); //判断是否动态图文件可用 if (!m_pMovie->isValid()) { //不可用 QMessageBox::critical(this, tr("动态图不可用"), tr("动态图格式不支持或读取出错,文件名为: %1").arg(strFileName)); //清除 delete m_pMovie; m_pMovie = NULL; return; //不可用就直接返回 } //动态图的总帧数 int nCount = m_pMovie->frameCount(); //如果动态图格式不支持计数,那么会返回 0 //打印帧数 qDebug() << tr("总帧数:%1").arg(nCount); //如果有统计帧数,那就设置滑动条上限 if (nCount > 0) { ui.horizontalSlider->setMaximum(nCount); } else { //获取不到帧数,默认当作 100 ui.horizontalSlider->setMaximum(100); } //把动态图设置给标签 ui.labelShow->setMovie(m_pMovie); //修改 bool 状态 m_bIsMovie = true; m_bIsPlaying = false; //还没点击播放开始的按钮 //待续 //关联播放时的信号 //播放出错信号 connect(m_pMovie, SIGNAL(error(QImageReader::ImageReaderError)), this, SLOT(RecvPlayError(QImageReader::ImageReaderError))); //播放的帧号变化信号 connect(m_pMovie, SIGNAL(frameChanged(int)), this, SLOT(RecvFrameNumber(int))); //将动态图片跳转到起始帧 if (m_pMovie->jumpToFrame(0)) { //跳转成功 //对于打头的帧,设置标签的矩形为帧的矩形 ui.labelShow->setGeometry(m_pMovie->frameRect()); } //如果跳转失败,槽函数 RecvPlayError() 会提示出错 } //播放开始按钮 void Qt_Show::on_pushButtonStart_clicked() { if (!m_bIsMovie) //不是动态图 { return; } if (m_bIsPlaying) //已经在播放了 { return; } //播放动态图 m_bIsPlaying = true; //开始播放状态 m_pMovie->start(); //播放 //打印动态图默认的播放循环轮数,0 代表不循环,-1 代表无限循环 qDebug() << tr("循环计数:%1").arg(m_pMovie->loopCount()); } //停止播放按钮 void Qt_Show::on_pushButtonStop_clicked() { if (!m_bIsMovie) //不是动态图 { return; } if (!m_bIsPlaying) //没有处于播放状态 { return; } //停止播放 m_bIsPlaying = false; m_pMovie->stop(); } //接收播放错误信号 void Qt_Show::RecvPlayError(QImageReader::ImageReaderError error) { //打印 qDebug() << tr("读取动态图错误的代码:%1").arg(error); //提示播放出错 QMessageBox::critical(this, tr("播放出错"), tr("播放动态图出错,文件名为: %1").arg(m_pMovie->fileName())); //回到停止状态 m_bIsPlaying = false; } //接收帧号变化信号 void Qt_Show::RecvFrameNumber(int frameNumber) { ui.horizontalSlider->setValue(frameNumber); }
- 问题1 都是图片,opensuse.png 能打开,opensuse.jpg 打开出错,这是为什么呢?
用这两张图片举例,不是为了说明 png 格式比 jpg 好,也不是为了说明我们例子代码有问题,
而是为了说明有些错误不在程序本身!
我们举例的 opensuse.png 和 opensuse.jpg 两张图片文件的数据是一模一样的,就是复制了一份,改了个扩展名而已。
opensuse 的图片原本就是 PNG 格式的,在下载的时候错误地保存为 opensuse.jpg。虽然操作系统的图片查看器、之前的 QTextBrowser 示例都能浏览这个错误扩展名的图片,但是 QPixmap::load() 函数根据 jpg 扩展名加载 opensuse.jpg 时出现了错误,因为这张图根本不是 jpg 图片。
这里打开 opensuse.jpg 出错,就是因为图片扩展名错了,与程序本身没关系。
那么 5.3.4 QTextBrowser 示例怎么能正确显示 opensuse.jpg 呢?那是因为它没有用 QPixmap::load() 函数加载图片,而是 QImage::loadFromData() 函数,感兴趣的读者可以看看 QImage::loadFromData() 函数帮助文档,它是直接从文件数据头判断文件格式,而不管扩展名是什么,因此能正确显示扩展名错误的图片。