ImageViewer 的主窗口
在本教程中,我们将学习如何从主窗口类的菜单和工具栏设置操作,就像上一个教程一样。但这一次,它稍微复杂一些,更接近实际应用。这主要基于Qt 教程,但旨在更详细地提供更多细节:使用设计器构建 ui,而不是直接键入代码。
开始
文件->新建文件或项目…
应用程序->Qt Gui 应用程序->选择…
我们将类重命名为ImageViewer。
点击下一步->完成。
这些是我们得到的文件:
我们打开imageviewer.pro,添加一行支持打印:
QT += core gui
QT += printsupport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ImageViewer
TEMPLATE = app
SOURCES += main.cpp\
imageviewer.cpp
HEADERS += imageviewer.h
FORMS += imageviewer.ui
这是main.cpp:
#include "imageviewer.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ImageViewer w;
w.show();
return a.exec();
}
在高亮行中,我们有一个ImageViewer类的事件。
这是头文件:imageviewer.h:
#ifndef IMAGEVIEWER_H
#define IMAGEVIEWER_H
#include <QMainWindow>
namespace Ui {
class ImageViewer;
}
class ImageViewer : public QMainWindow
{
Q_OBJECT
public:
explicit ImageViewer(QWidget *parent = 0);
~ImageViewer();
private:
Ui::ImageViewer *ui;
};
#endif // IMAGEVIEWER_H
请注意,我们有一个命名空间UI,我们的ImageViewer在UI范围内。此外,在标头中,我们将指向Ui::ImageViewer的指针声明为私有成员ui。
让我们通过双击imageviewer.ui打开Designer。我们想把滚动区放到主窗口中:
然后,还有一个标签小部件。
QLabel通常用于显示文本,但它也可以显示图像。
QScrollArea提供围绕另一个小部件的滚动视图。如果子部件超出框架的大小,QScrollArea 会自动提供滚动条。
ImageViewer 的初始预览
让我们来看看它是如何工作的。
这是仅用于显示的最小版本。下面的代码是ImageViewer的构造函数,它是最小的。
ImageViewer::ImageViewer(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ImageViewer)
{
ui->setupUi(this);
QImage image("C:/TEST/GoldenGate.png");
ui->imageLabel->setPixmap(QPixmap::fromImage(image));
}
当然,我们需要在imageviewer.h中指向 QScroll 和 QLabel 的两个指针:
private:
Ui::ImageViewer *ui;
QLabel *imageLabel;
QScrollArea *scrollArea;
当我们运行代码时,我们得到:
现在,我们知道该怎么做了。
- 用于选择图像的菜单
- 为此,我们需要一种文件打开对话框
- 此外,我们可能想要玩图像,例如放大/缩小
- 如果可能,我们要打印图像
滚动区域和标签的更多工作
这一次,我们使用代码而不是 Designer 设置 QScrollArea 和 QLable。
// imageview.cpp
#include "imageviewer.h"
#include "ui_imageviewer.h"
ImageViewer::ImageViewer(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ImageViewer)
{
ui->setupUi(this);
imageLabel = new QLabel;
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
imageLabel->setScaledContents(true);
scrollArea = new QScrollArea;
scrollArea->setBackgroundRole(QPalette::Dark);
scrollArea->setWidget(imageLabel);
setCentralWidget(scrollArea);
setWindowTitle(tr("Image Viewer"));
resize(500, 400);
}
ImageViewer::~ImageViewer()
{
delete ui;
}
setBackgroundRole()方法让我们为背景使用颜色角色,这意味着应用于小部件的样式的预定义颜色之一。
setSizePolicy()将大小策略设置为策略。大小策略描述了在布局中排列时项目应如何水平和垂直增长。我们将imageLabel的尺寸策略设置为忽略,使用户能够在“适合窗口”选项打开时将图像缩放到他们想要的任何尺寸。否则,默认大小策略(首选)将在滚动区域变得小于标签的最小大小提示时出现滚动条。
setScaledContents(bool)决定标签是否将缩放其内容以填充所有可用空间。当启用并且标签显示像素图时,它将缩放像素图以填充可用空间。此属性的默认值为 false。在这里,我们确保标签将缩放其内容以填充所有可用空间,以使图像在缩放时能够正确缩放。如果我们省略设置imageLabel的scaledContents属性,放大会放大 QLabel,但保留像素图的原始大小,暴露 QLabel 的背景。
setCentralWidget (ui->scrollArea)使 scrollArea 成为 MainWindow 的中心小部件。
设计菜单
使用 Image Viewer 应用程序,用户可以查看他们选择的图像。文件菜单使用户可以:
- 打开… – 打开图像文件
- 打印… – 打印图像
- 退出 – 退出应用程序
加载图像后,查看菜单允许用户:
- 放大 – 将图像放大 25%
- 缩小 – 将图像缩小 25%
- 正常尺寸 – 以原始尺寸显示图像
- 适合窗口 – 拉伸图像以占据整个窗口
此外,我们可能还有 Help 菜单,以及 About 为用户提供有关 Image Viewer 示例的信息
让我们通过双击imageviewer.ui打开Designer来放置菜单栏和操作。在顶部菜单中输入“文件”,在“文件”菜单下输入“打开…”。我们需要按 Enter 来对菜单进行真正的更改。请注意,在底部的动作编辑器中,已经创建了一个名为actionOpen的新动作。
让我们将对象名称改为openAct,并创建一个快捷方式(我们应该输入真正的组合键,而不是输入每个字符),如下图所示:
请注意,我们可以通过双击动作编辑器窗口中的项目或鼠标右键单击该项目来获得“编辑动作”窗口,然后选择“编辑…”
C++ 中的等效代码如下所示:
openAct = new QAction(tr("&Open...;"), this);
openAct->setShortcut(tr("Ctrl+O"));
默认情况下,翻译tr()设置为启用。
使用 Create 进行的工作不仅仅是编码!
接下来是打印…:
对于“打印”菜单,我们最初需要将其设置为禁用(未选中)。稍后,在加载图像后,它将被重置为启用:
同样,等效代码应如下所示:
printAct = new QAction(tr("&Print...;"), this);
printAct->setShortcut(tr("Ctrl+P"));
printAct->setEnabled(false);
对于退出菜单,我们通过单击图标(新建)或右键单击项目-> 选择新建…而不是直接双击顶部菜单区域来打开“编辑操作”弹出窗口:
等效代码:
exitAct = new QAction(tr("E&xit;"), this);
exitAct->setShortcut(tr("Ctrl+Q"));
但是,当我们运行代码并查看菜单时,“退出”不在顶部菜单中。我们可以再次仔细查看Action Editor:
它被标记为不用于菜单。因此,我们需要拖动exitAct,然后将其放在顶部菜单的Print…项下。然后它将位于顶部菜单项中并标记为已使用。
这是动作编辑器的最终版本:
等效代码应如下所示:
openAct = new QAction(tr("&Open...;"), this);
openAct->setShortcut(tr("Ctrl+O"));
printAct = new QAction(tr("&Print...;"), this);
printAct->setShortcut(tr("Ctrl+P"));
printAct->setEnabled(false);
exitAct = new QAction(tr("E&xit;"), this);
exitAct->setShortcut(tr("Ctrl+Q"));
zoomInAct = new QAction(tr("Zoom &In; (25%)"), this);
zoomInAct->setShortcut(tr("Ctrl+=")); //(Ctrl)(+)
zoomInAct->setEnabled(false);
zoomOutAct = new QAction(tr("Zoom &Out; (25%)"), this);
zoomOutAct->setShortcut(tr("Ctrl+-")); //(Ctrl)(-)
zoomOutAct->setEnabled(false);
normalSizeAct = new QAction(tr("&Normal; Size"), this);
normalSizeAct->setShortcut(tr("Ctrl+S"));
normalSizeAct->setEnabled(false);
fitToWindowAct = new QAction(tr("&Fit; to Window"), this);
fitToWindowAct->setEnabled(false);
fitToWindowAct->setCheckable(true);
fitToWindowAct->setShortcut(tr("Ctrl+F"));
aboutAct = new QAction(tr("&About;"), this);
aboutQtAct = new QAction(tr("About &Qt;"), this);
其实上面的代码和我们做的不一样。我们隐式添加了菜单栏,顶部菜单的每个项目都有其子菜单。因此,需要更多的编码(如下所示)来实现与我们使用 Designer 所做的相同的操作:
fileMenu = new QMenu(tr("&File;"), this);
fileMenu->addAction(openAct);
fileMenu->addAction(printAct);
fileMenu->addSeparator();
fileMenu->addAction(exitAct);
viewMenu = new QMenu(tr("&View;"), this);
viewMenu->addAction(zoomInAct);
viewMenu->addAction(zoomOutAct);
viewMenu->addAction(normalSizeAct);
viewMenu->addSeparator();
viewMenu->addAction(fitToWindowAct);
helpMenu = new QMenu(tr("&Help;"), this);
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
menuBar()->addMenu(fileMenu);
menuBar()->addMenu(viewMenu);
menuBar()->addMenu(helpMenu);
实际上,菜单结构如下所示:
如果我们运行代码,到目前为止我们制作的菜单如下所示:
信号和插槽实现
我们只在创建时启用openAct和exitAct,其他的会在图像加载到应用程序后更新。此外,我们使fitToWindowAct 成为可检查的。
我们将在下一个教程中继续。