Qt实现图片浏览器
Qt实践3: 图片浏览器
引言
因课程教学,需要利用Qt做图形界面设计(GUI)。自学Qt两月有余,发现现有很多资料,讲述C++程序设计QT项目的较多,不利于新手入门,特别是对于C++编程较弱的学生,上手较难。因此,我将所学的资料,进行归纳整理,总结出一种利用Qt Creator平台的UI设计模式进行Qt项目设计的方法,其中信号与槽函数的编写,也利用槽函数自动连接的方法,大大减少C++代码的编写。该GUI设计方法简捷,易于新手学习。
第一个实践项目是密码登录窗设计,主要讲述 QtCreator的基本操作、对话框Dialog窗体的创建,以及两个窗口的切换显示方法。
第二个实践项目是简易计算器的设计,着重讲述Widget窗体的界面设计与布局方法、槽函数编写方法。
本项目设计着重讲述带有菜单栏、工具栏和铆接组件的MainWindow窗体设计、信号与槽函数自动配置,以及槽函数编程方法。
本实践项目是图片浏览器设计,借鉴于[寒江雪Charles的图片浏览器],该文章提供的源代码,着重利用C++代码方式编写程序。这里对其进行简化,充分利用QtCreator的UI设计模式,减少编写的代码,便于新手学习。
一、 实验目的
- 熟悉 QtCreator的基本操作,熟练掌握信号与槽在应用程序中的使用。
- 熟练Qmainwindow窗口设计方法
- 掌握图片浏览器的Qt设计方法
二、 实验内容
- 学习 Qt 资源系统使用方法。
- 使用 QtCreator,设计图片浏览器。
三、实现步骤
1. 创建工程
打开 QtCreator,新建项目,进行以下操作:
选择“Qt Widgets Application”
项目名称“ImageViewer”,路径“…/QImageViewer”
选择类“QmainWindow”,名称“ImageViewer”
并选中“创建界面”
2. 添加资源文件
将图片文件夹“/images”复制到项目路径“…/QImageViewer”中。(该图片文件夹来自于[[寒江雪Charles的图片浏览器]],放置了菜单操作图标)
右击项目名称,选择“Add New”,打开新建文件界面。
选择模板Qt->Qt Resource File,名称为“Images”,路径选择上步复制的图片文件夹“/images”,默认选择添加到当前项目中。 窗口正下方,点击“添加”,点击“添加前缀”,修改前缀为“/images”.
再点击“添加”,选择“添加文件”,全部选中当前图片(ctrl+A),完成资源文件的创建。
3.菜单栏设计
菜单栏的构成:标题栏、菜单栏、工具栏、锚接部件、中心部件
双击项目树中的imageviewer.ui文件名,进入设计模式。
1)创建菜单栏和选项
窗口界面上,双击“在这里输入”,可输入菜单栏的名称,回车后进入当前菜单选项设计界面,再双击“在这里输入”,可创建当前菜单下各选项。
这里,创建菜单栏和菜单下选项分别为:
创建菜单栏File,选项有:打开,关闭,退出。(中文不能直接输入,可用复制、黏贴方式输入)。
创建菜单栏operate,选项有:上一张,下一张,左旋,右旋,放大,缩小。
创建菜单栏About,选项有:Qt
2)添加菜单选项的图标
双击下方动作编辑器窗口的“actionopen”,弹出编辑动作窗口,点击图标选项“…”,弹出图片选择窗口,选择合适的图片。(如,add.png)
类似操作,分别给选项:打开,关闭,退出;上一张,下一张,左旋,右旋,放大,缩小;About Qt,都选择合适的图标的图片。
3)添加快捷键
如上,打开编辑动作的窗口,在Shortcut空白处按住键盘组合键,即可输入对应的快捷键。比如,这里按住Ctrl和O键,则设置打开选项的快捷键是Ctrl+O
分别给全部菜单选项添加对应的快捷键。(也可以不添加)
下方的动作编辑器窗口中,修改各菜单选项的名称。最后,如下图所示。
4.工具栏设计
下方的动作编辑器窗口中,选中某图标,直接拖到上方窗口工具栏的空白处即可。
5.功能实现
信号与槽函数自动创建
下方的动作编辑器窗口中,右击某actionOpen,选择“转到槽”,默认选择“triggered()”信号,自动创建槽函数:void ImageViewer::on_actionOpen_triggered()。该槽函数是空函数,需要编写程序实现动作事件。
相同操作,依次创建其他action的空白槽函数。
编写各槽函数的功能程序
多个action的槽函数,都要先进行打开图片、读取图片信息的操作,因此这里先进行2个函数的定义
int loadImageResource(void)函数用于打开本地某文件夹中的一个图片;
int getFileInfoList(void)函数用于读取图片信息。
1) 打开本地某文件夹中的一个图片。
调用QFileDialog::getOpenFileName函数,提供了打开文件窗口。程序如下:
int ImageViewer::loadImageResource(void)
{
//调用标准对话框QFileDialog类,打开一个图片
filename = QFileDialog::getOpenFileName(this, tr("Select image:"),
"D:\\Documents\\Pictures", tr("Images (*.png *.bmp *.jpg *.gif)"));
if (filename.isEmpty()) {
return -1 ;
}
//QImage类封装了对于一般图像像素级的操作,图像显示则使用QPixmap。
if (!image.load(filename)) {
QMessageBox::information(this, tr("Error"), tr("Open file error")); //错误提示
return -1 ;
}
//QImage转换成QPixmap
pixmap = QPixmap::fromImage(image);
size = pixmap.size();
/* get file list */
getFileInfoList();
return 0;
}
解释:
QFileDialog::getOpenFileName函数的调用格式,自行百度吧,这里调用它,产生一个对话框,其标题为"Select image:",默认打开路径是 “D:\Documents\Pictures”,只能打开*.png *.bmp *.jpg *.gif格式的图片。选择某图片打开后,该图片名称赋给filename。
image.load(filename)则是根据文件名导入图片像素信息,赋值给变量image
Qimage图片信息需要转换成QPixmap形式,才能显示,调用转换函数:
变量pixmap = QPixmap::fromImage(image);
变量size 用于保存pixmap 的像素长和宽值。
getFileInfoList()函数,是另一个自定义的函数,用于读取打开后的本地图片文件夹目录等信息。
2) 读取图片所在文件夹的路径和目录列表信息
自定义的函数:getFileInfoList(void),程序编写:
int ImageViewer::getFileInfoList(void)
{
QFileInfo info; //定义变量
QFileInfoList infoList;
path = QFileInfo(filename).absolutePath(); //返回绝对路径
dir = QFileInfo(filename).absoluteDir(); //返回目录名称
/* clear list */
fileInfoList.clear();
infoList = dir.entryInfoList(QDir::Files); //列出dir(path)目录文件下所有文件和目录信息,存储到infoList 容器
//进行文件夹递归遍历,将内容存入infoList 容器
for (int i = 0; i < infoList.count(); i++) { //文件数目:fileInfo.count();
info = infoList.at(i); //文件名称:fileInfo.at(i)
QString suffix = info.suffix(); //后缀名
if (suffix == "jpg" || suffix == "bmp" || suffix == "png") {
fileInfoList.append(info);
}
}
QFileInfo curImageInfo = QFileInfo(filename);
for (int j = 0; j <fileInfoList.count(); j++) {
info = fileInfoList.at(j); //进行文件夹递归遍历
if (info.fileName() == curImageInfo.fileName()) {
index = j; //记录索引值
}
}
return 0 ;
}
解释:
这里要调用QFileInfo、QFileInfoList类,
path = QFileInfo(filename).absolutePath(); //返回绝对路径
dir = QFileInfo(filename).absoluteDir(); //返回目录名称
infoList = dir.entryInfoList(QDir::Files); //列出dir(path)目录文件下所有文件和目录信息,存储到infoList 容器
.count(); //文件总数
.at(i); //读取文件名称
fileInfoList.append(info); //fileInfoList文件列表中添加文件名info
3)变量、函数预定义,以及初始化
上面两个函数中使用了多个变量、类及其函数,需要在imageviewer.h头文件预定义,指定库文件。
因此,imageviewer.h头文件中添加库文件引用:
添加变量定义
public:
int index;
int angle; //后面设计左/右旋槽函数时要用到
QSize size;
QString filename;
QString path;
QDir dir;
QFileInfo fileInfo;
QFileInfoList fileInfoList;
QImage image;
QPixmap pixmap;
添加函数定义:
private:
/* init param /
void initImageResource(void); //初始化函数,接下来会讲解,这里一并先预定义
/ open a image /
int loadImageResource(void);
/ get file info list from current path */
int getFileInfoList(void);
各变量,需要在程序设计开始时进行初始化处理,所以编写初始化函数initImageResource(void)为:
void ImageViewer::initImageResource(void)
{
index = -1;
angle = 0;
size = QSize(0, 0);
filename.clear();
path.clear();
}
void initImageResource(void)初始化函数一般放在ImageViewer::ImageViewer(QWidget *parent) 窗口描述中:
{
ui->setupUi(this);
//初始化
initImageResource();
}
4)action “打开”的槽函数的程序设计
void ImageViewer::on_actionOpen_triggered()
{
loadImageResource(); //打开某目录中的图片
//Label标签上显示图片
ui->imageLabel->setPixmap(pixmap);
ui->imageLabel->resize(size);//实现图片自适应大小
//设置窗口的标题名称
setWindowTitle(QFileInfo(filename).fileName() + tr(" - imageViewer"));
}
解释:
ui->imageLabel是在菜单窗口中间拖放的label标签,用于图片显示。
resize(size)函数是调整图片自适应大小的变化。前面需要引用QSize
5)action “关闭”的槽函数的程序设计
void ImageViewer::on_actionClose_triggered()
{
//清除图片显示
ui-> imageLabel->clear();
//读取资源文件中+号图片
image.load(":/images/add.png");
pixmap = QPixmap::fromImage(image);
size = pixmap.size();
ui->imageLabel->setPixmap(pixmap);
ui->imageLabel->resize(size);//实现图片自适应大小
setWindowTitle(tr("imageViewer"));
}
6)action “退出”的槽函数的程序设计
void ImageViewer::on_actionExit_triggered()
{
close();
}
7)action “左旋”的槽函数的程序设计
void ImageViewer::on_actionLeft_triggered()
{
//预先加载图片后,已得到image、size等数据,这里直接进行左旋处理
QImage imgRotate; //定义局部变量
QMatrix matrix;
angle +=3;
angle=angle%4; //取余数
matrix.rotate(angle*90); //得到旋转角度,逆时针旋转
imgRotate = image.transformed(matrix); //尺度变换函数transformed(matrix)
pixmap = QPixmap::fromImage(imgRotate);
size = pixmap.size();
//Label标签上显示图片
ui->imageLabel->setPixmap(pixmap);
ui->imageLabel->resize(size);//实现图片自适应大小
return ;
}
action “右旋”的槽函数,类同,修改angle +=1即可。
8)action “放大”的槽函数的程序设计
void ImageViewer::on_actionEnlarge_triggered()
{
//加载图片后,已得到image、size等数据,这里直接进行处理
QImage imgScaled;
QImage imgRotate;
QMatrix matrix;
// 调用image.scaled函数,进行尺度变换
imgScaled = image.scaled(size.width() *1.2, //放大倍数1.2
size.height() * 1.2,
Qt::KeepAspectRatio);
/* modify angle */
matrix.rotate(angle * 90); //读取当前旋转角度
imgRotate = imgScaled.transformed(matrix); //变换
pixmap = QPixmap::fromImage(imgScaled);
size = pixmap.size();
//Label标签上显示图片
ui->imageLabel->setPixmap(pixmap);
ui->imageLabel->resize(size);//实现图片自适应大小
return ;
}
action “缩小”的槽函数,与此类同,修改放大倍数1.2为0.8即可。
9)action “上一张”的槽函数的程序设计
void ImageViewer::on_actionLast_triggered()
{
index = index - 1; //更新索引值,减一
int count = fileInfoList.count(); //读取文件个数的统计值
//判断是否第一张图片
if (index < 0) {
QMessageBox::information(this, tr("Tip"), tr("This is the first image."));
index = count - 1;
}
//读取当前路径path下索引值index – 1的文件名
filename.clear();
filename.append(path);
filename += "/";
filename += fileInfoList.at(index).fileName();
//根据文件名加载图片,否则错误提示
if (!image.load(filename)) {
QMessageBox::information(this, tr("Error"), tr("Open file error"));
return ;
}
//QImage转换成QPixmap
pixmap = QPixmap::fromImage(image);
size = pixmap.size();
//Label标签上显示图片
ui->imageLabel->setPixmap(pixmap);
ui->imageLabel->resize(size);//实现图片自适应大小
//标题栏上,添加图片名和- imageViewer
setWindowTitle(QFileInfo(filename).fileName() + tr(" - imageViewer"));
return;
}
action “下一张”的槽函数,与此类同,修改index = index+1;修改判断语句(是否是最后一张图片):
if (index == count) {
QMessageBox::information(this, tr(“Tip”), tr(“This is the last image.”));
index = 0;
}
10)action “Qt”的槽函数的程序设计
这里需要构建QDockWidget窗口部件(锚接部件),它是放置在QMindow窗口上的工具窗口,可移动和悬浮。
void ImageViewer::on_actionQt_triggered()
{
//构建停靠窗口名AboutMe,指定父类为this主窗口
QDockWidget *AboutMe = new QDockWidget(tr("About Qt"),this); AboutMe->setWindowTitle(tr("About Me"));
//设置停靠窗口特性,可移动,可关闭,可漂浮
AboutMe->setFeatures(QDockWidget::AllDockWidgetFeatures);
//设置窗口停靠位置
AboutMe->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
//构建显示文本myInfo
QTextEdit *myInfo = new QTextEdit(tr("<br>Welcom</br><br>blog address:https://blog.csdn.net/leyan118</br>"));
//构建显示文本myInfo为锚接部件
AboutMe->setWidget(myInfo);
addDockWidget(Qt::RightDockWidgetArea, AboutMe); //右侧显示
}
使用QDockWidget以及QTextEdit,需要在imageviewer.h头文件中引入库文件QTextEdit、QDockWidget。
功能自行扩展:
- 自动播放。(提示,需要使用定时器)
- 其他功能扩展:图像扭曲,或图像处理(灰度变换等)