首页 Qt 学习之路 2 Qt 学习之路 2(7):MainWindow 简介

Qt 学习之路 2(7):MainWindow 简介

37 4K

前面一篇大致介绍了 Qt 各个模块的相关内容,目的是对 Qt 框架有一个高屋建瓴般的了解。从现在开始,我们将开始尝试使用 Qt 开始新的历程。由于我们已经比较详细地介绍过信号槽的相关内容,因此我们可以用一个新的程序开始进一步的学习,同时对信号槽有一个比较深入的理解。

QMainWindow是 Qt 框架带来的一个预定义好的主窗口类。所谓主窗口,就是一个普通意义上的应用程序(不是指游戏之类的那种)最顶层的窗口。比如你现在正在使用的浏览器,那么主窗口就是这个浏览器窗口。试着回想一下经典的主窗口,通常是由一个标题栏,一个菜单栏,若干工具栏和一个任务栏。在这些子组件之间则是我们的工作区。事实上,QMainWindow正是这样的一种布局。

下面我们新建一个工程。还记得在新建工程的时候,Qt Creator 通常会帮助我们创建一个MainWindow吗?我们曾经为了介绍信号槽,将main()函数做了修改。现在我们直接使用 Qt Creator 生成的代码来编译运行一下:

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    MainWindow win;
    win.show();

    return app.exec();
}

在 openSUSE 上运行结果如下:

Main window

我们仔细看看这个窗口。虽然不太明显,但它实际上分成了几个部分:

Main Window Struct

主窗口的最上面是 Window Title,也就是标题栏,通常用于显示标题和控制按钮,比如最大化、最小化和关闭等。通常,各个图形界面框架都会使用操作系统本地代码来生成一个窗口。所以,你会看到在 KDE 上面,主窗口的标题栏是 KDE 样式的;在 Windows 平台上,标题栏是 Windows 风格的。如果你不喜欢本地样式,比如 QQ 这种,它其实是自己将标题栏绘制出来,这种技术称为 DirectUI,也就是无句柄绘制,这不在本文的讨论范畴。Window Title 下面是 Menu Bar,也就是菜单栏,用于显示菜单。窗口最底部是 Status Bar,称为状态栏。当我们鼠标滑过某些组件时,可以在状态栏显示某些信息,比如浏览器中,鼠标滑过带有链接的文字,你会在底部看到链接的实际 URL。

除去上面说的三个横向的栏,中间是以矩形区域表示。我们可以看出,最外层称为 Tool Bar Area,用于显示工具条区域。之所以是矩形表示,是因为,Qt 的主窗口支持多个工具条。你可以将工具条拖放到不同的位置,因此这里说是 Area。我们可以把几个工具条并排显示在这里,就像 Word2003 一样,也可以将其分别放置,类似 Photoshop。在工具条区域内部是 Dock Widget Area,这是停靠窗口的显示区域。所谓停靠窗口,就像 Photoshop 的工具箱一样,可以停靠在主窗口的四周,也可以浮动显示。主窗口最中间称为 Central Widget,就是我们程序的工作区。通常我们会将程序最主要的工作区域放置在这里,类似 Word 的稿纸或者 Photoshop 的画布等等。

对于一般的 Qt 应用程序,我们所需要做的,就是编写我们的主窗口代码,主要是向其中添加各种组件,比如菜单、工具栏等,当然,最重要的就是当中的工作区。当我们将这些都处理完毕之后,基本上程序的工具也可以很好地实现。

通常我们的程序主窗口会继承自QMainWindow,以便获得QMainWindow提供的各种便利的函数。这也是 Qt Creator 生成的代码所做的。

由于QMainWindow这个类在 Qt 5 中并没有什么改变,因此上面的代码可以直接拿到 Qt 4 中进行编译。事实上,我们使用 Qt Creator 生成的代码也是可以直接在 Qt 4 中编译。只不过需要注意一点:Qt 4 中没有 widgets 模块,因此在 pro 文件中,我们通常需要这么来写:

QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET    = qtdemo
TEMPLATE  = app

SOURCES  += main.cpp \
        mainwindow.cpp

HEADERS  += mainwindow.h

简单解释一下 pro 文件。首先,我们定义了 QT,用于告诉编译器,需要使用哪些模块。这些模块都在前面章节中有过介绍。我们通常需要添加 core 和 gui。第二行,如果 Qt 的主版本号(QT_MAJOR_VERSION)大于 4,也就是 Qt 5,则需要另外添加 widgets(因为在 Qt 5 中,所有组件都是在 widgets 模块定义的)。TARGET 是生成的程序的名字。TEMPLATE 是生成 makefile 所使用的模板,比如 app 就是编译成一个可执行程序,而 lib 则是编译成一个链接库(默认是动态链接库)。SOURCES 和 HEADERS 顾名思义,就是项目所需要的源代码文件和头文件。现在,我们只需使用默认的 pro 文件即可。以后随着项目的不断增大,pro 文件通常会非常复杂。

37 评论

Anonymous 2012年8月29日 - 19:26

不知道用qt5伪造ribon界面会不会很复杂,大概和android上自己实现非原声组件差不多的过程吗

回复
DevBean 2012年8月29日 - 20:18

Ribbon 界面有 Qt 的实现,不过是收费的商业库,即 QtitanRibbon。不过如果需要的免费的话,只能自己做一个了。

回复
Hanfucius 2012年11月7日 - 20:21

wxWidgets可以实现Ribbon界面啊~Qtitan原来是收费的啊。。。记得看过一个Ribbon实现的列表

回复
DevBean 2012年11月8日 - 10:54

wxWidgets 可以直接调用本地库(话说 Qt 应该也是可以的,就是要整合 win32 API 了)。

回复
Hanfucius 2012年11月7日 - 20:25

最近在学Qt。在图书馆借的丁林松的一本《Qt4图形设计与嵌入式开发》,看了几章发现很多是翻译的文档和例子,顿时没兴趣看了。优酷还有他的视频。豆子现在就搞Qt5了,可敬啊

回复
DevBean 2012年11月8日 - 10:53

Qt 5 也已经不远,了解一下呗,呵呵

回复
路过 2013年3月24日 - 21:57

“出去”上面说的三个横向的栏-----这句话,应该是“除去”。
大哥你用的拼音打字吗?错别字挺多的。

回复
豆子 2013年3月25日 - 09:17

不好意思,的确是拼音

回复
Zeck 2013年4月30日 - 22:22

对于新手帮助很大 感谢博主 支持下LZ出Qt Quick的教程 😀

回复
豆子 2013年5月2日 - 10:51

嗯嗯,感谢支持哦~以后会的!

回复
梓涵 2013年6月11日 - 00:44

十分敬佩博主的奉献精神,最近打算主攻Qt5了

回复
搜火 2013年8月27日 - 01:23

博主写的真好,不知道可以转载吗?不知道博主有没有出书的打算。

回复
豆子 2013年8月27日 - 14:22

欢迎转载!出书的话目前暂无计划 ;-P

回复
Xavier 2013年12月1日 - 20:57

文章清晰易懂,博主真是個好老師!

回复
2013年12月8日 - 17:22

请问在”main.cpp“的第六行”QApplication app;“,
为什么没有指定参数(argc,argv)呢?
就像”QApplication app(argc, argv);“这样,
否则貌似无法通过编译。

回复
豆子 2013年12月9日 - 10:27

感谢指出,这的确是个错误

回复
eden 2013年12月24日 - 12:34

豆子你好,请教一个问题,我在windows7安装了最近的Qt5.2,然后再creator上新建了一个空的Qt醒目,添加了一个main.cpp文件,为什么我的#includes等都是报错的,显示NO such file,我在.pro文件按里也添加了QT += 。。。。。‘谢谢

回复
豆子 2013年12月24日 - 23:10

一般是由于没有找到 Qt include 目录,可能是环境变量哪里错了。或者你安装完之后没有在 Qt Creator 中配置 Qt 版本。

回复
Johnny 2014年4月30日 - 21:49

博主你好,我在学习previewer实例里有点不明白,想请教博主,望回复,谢谢!
有三个源文件,main.cpp,mainwindow.cpp, previewer.cpp 和UI文件夹previewer.ui,我在main.cpp里看到mainwindow.show(),是什么机制在显示界面时显示的是previewer.ui,我在mainwindow.cpp里没有看到相关显示ui的语句,我是菜鸟,望回复,谢谢!

回复
george 2014年5月24日 - 17:03

请问一下那个资源文件怎么不会自动生成?自己添加的话是添加到编译目录还是文件存放的目录?图片无法显示怎么办?

回复
豆子 2014年5月27日 - 09:18

资源文件是自己添加的,你可以在 IDE 中添加 Qt 资源文件即可。如果添加之后没有生成,重新运行一下 qmake 试试(项目上点右键有运行 qmake 项)。

回复
george 2014年5月24日 - 17:04

你好,还有,为什么我的QMessageBox::information(this,tr("Information"),tr("Open"));是无效的?

回复
豆子 2014年5月27日 - 09:18

具体是什么错误?

回复
tanny 2015年1月9日 - 13:20

楼主,请教一下 我用的是qt5.4.0 msvc2010_opengl版本的,下了对应的qt addin插件,在vs2010中开发。 我的电脑是xp的。
环境变量都设置过了,然后你的hello world 加上include能编译
下方的你这篇的代码中(是上面那个)老是出现:fatal error C1083: 无法打开包括文件:“mainwindow.h”: No such file or directory
有些人说是因为include路径没有设置对。 但是我的lib和include都检查过没错的呀,还有些人说qt4的程序迁移到qt5中会出现这个错误。
光是搭建这个 vs2010 + qt5.4 的环境就已经搞了好几天,真是郁闷。希望能得到你的帮助,非常感谢啊!
另外还想问下,咱这边的代码是基于qt4的吗? 但是有些上边分明注释了//qt5 的啊。。

回复
tanny 2015年1月9日 - 13:22

改一下
“环境变量都设置过了,然后你的hello world 加上include能编译通过”

回复
G1enY0ung 2016年2月3日 - 09:35

博主前文已经提及了,Qt4和Qt5同时介绍

回复
毕学鸠 2015年1月29日 - 16:18

博主您好!请问MainWindow的构造函数中
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
其中第二行 : QMainWindow(parent) 这个该怎么理解?是初始化列表吗?是继承了QMainWindow这个成员,然后用 parent 指针把它初始化?

回复
Napchat 2015年9月16日 - 15:55

类才能继承,构造函数中显然应该是初始化基类成员,在构造派生类实例之前就将基类继承的成员给初始化了。

回复
ben 2016年7月23日 - 11:18

奇怪,为什么用qmake生成的.pro文件与QtCreator生成的内容和格式都有区别呢?qmake生成的.pro文件在qt5下还要手动添加 QT += widgets,而QtCreator会自动生成greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

//qmake生成的.pro文件
TEMPLATE = app
TARGET = 07
INCLUDEPATH += .

# Input
HEADERS += mainwindow.h
SOURCES += main.cpp mainwindow.cpp

回复
cxtan 2019年9月23日 - 18:13

豆子,请教下 在qt pro文件里边target = 这是一个中文程序,编译出来程序名字会是乱码,这个怎么办。

回复
豆子 2019年11月2日 - 16:31

Qt 的编译到现在对中文支持也不是很好,使用英文名字能避免很多奇怪的问题

回复
chenchen 2020年2月2日 - 20:59

豆子先生你好,我做了几年工控自动化,现在想转行,个人喜欢写代码,大学学过C/C++,此外自学过数据结构算法,于是就选择学习QT,你能简单说一下QT的应用前景吗?如果豆子先生说没必要学我就不学了。

回复
豆子 2020年2月7日 - 16:55

这个我不好所,因为我不是工控领域的,所以不确定 Qt 在工控领域的应用前景。Qt 在嵌入式领域应用还是很广泛的。不过现在也很少有紧靠一门语言或一个框架就能适应全部场景的情形,很多都是混合应用。

回复
李生 2020年7月30日 - 13:35

豆子老师,你好,我现在的页面逻辑设计了三层,我怎么可以实现点击第三层的右上角关闭按钮,直接返回第一层主界面,目前点击第三层界面关闭,它会回到第二层,需要再次点击一次第二层的叉号关闭才能返回第一层主界面。目前我的知识储备理解,这个MainWindow文件可以设置信号槽吗,或者怎么去引导实现点击叉号后,再次触发点击,就可以实现了。

回复
豆子 2020年7月30日 - 15:02

如果是类似对话框的实现,主窗口打开对话框,对话框再弹出新的对话框,这样的话,由于第三层对话框是由第二层打开的,所以第二层可以拿到第三层的指针。这样就可以使用信号槽机制,第三层关闭时发出信号,与第二层自己的关闭函数连接。或者利用 parent 指针,可以把第二层作为 parent 指针传给第三层,这样就可以调用 parent 指针的任意函数(不过这样的耦合度会高一些)。

回复
梅西 2020年8月19日 - 09:45

我下载的qt5.14.2和vs2019,然后我也按照网上的配置了,可是为什么我的qt creator依然是不能调试?

回复
LR 2021年9月14日 - 16:35

想问一下问题解决了没有,我也是遇到类似的错,VS2019 添加 QT 的库,用VS可以建QT的项目,可以看到QT Designer能打开,拖控件什么的都没有什么问题,但是运行时一直报错:无法打开源文件 "ui_QtGuiApplication1.h" ,网上也查了不少方法,也都试了,问题就是没解决

回复

回复 DevBean 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2