首页 Qt 学习之路 2 Qt 学习之路 2(12):菜单栏、工具栏和状态栏

Qt 学习之路 2(12):菜单栏、工具栏和状态栏

38 9

在之前的《添加动作》一文中,我们已经了解了,Qt 将用户与界面进行交互的元素抽象为一种“动作”,使用QAction类表示。QAction可以添加到菜单上、工具栏上。期间,我们还详细介绍了一些细节问题,比如资源文件的使用、对象模型以及布局管理器。这一节则是详细介绍关于菜单栏、工具栏以及状态栏的相关内容。

我们假设窗口还是建立在QMainWindow类之上,这会让我们的开发简单许多。当然,在实际开发过程中,QMainWindow通常只作为“主窗口”,对话框窗口则更多地使用QDialog类。我们会在后面看到,QDialog类会缺少一些QMainWindow类提供方便的函数,比如menuBar()以及toolBar()

下面还是回到《添加动作》一文中的代码片段:

openAction = new QAction(QIcon(":/images/doc-open"), tr("&Open..."), this);
openAction->setShortcuts(QKeySequence::Open);
openAction->setStatusTip(tr("Open an existing file"));
connect(openAction, &QAction::triggered, this, &MainWindow::open);

QMenu *file = menuBar()->addMenu(tr("&File"));
file->addAction(openAction);

QToolBar *toolBar = addToolBar(tr("&File"));
toolBar->addAction(openAction);

我们看到,使用menuBar()函数,Qt 为我们创建了一个菜单栏。menuBar()QMainWindow提供的函数,因此你是不会在QWidget或者QDialog中找到它的。这个函数会返回窗口的菜单栏,如果没有菜单栏则会新创建一个。这也就解释了,为什么我们可以直接使用menuBar()函数的返回值,毕竟我们并没有创建一个菜单栏对象啊!原来,这就是menuBar()为我们创建好并且返回了的。

Qt 中,表示菜单的类是QMenuBar(你应该已经想到这个名字了)。QMenuBar代表的是窗口最上方的一条菜单栏。我们使用其addMenu()函数为其添加菜单。尽管我们只是提供了一个字符串作为参数,但是 Qt 为将其作为新创建的菜单的文本显示出来。至于 & 符号,我们已经解释过,这可以为菜单创建一个快捷键。当我们创建出来了菜单对象时,就可以把QAction添加到这个菜单上面,也就是addAction()函数的作用。

下面的QToolBar部分非常类似。顾名思义,QToolBar就是工具栏。我们使用的是addToolBar()函数添加新的工具栏。为什么前面一个是menuBar()而现在的是addToolBar()呢?因为一个窗口只有一个菜单栏,但是却可能有多个工具栏。如果我们将代码修改一下:

QToolBar *toolBar = addToolBar(tr("&File"));
toolBar->addAction(openAction);

QToolBar *toolBar2 = addToolBar(tr("Tool Bar 2"));
toolBar2->addAction(openAction);

我们看到,现在有两个工具栏了:

在 QMainWindow 中添加两个 QToolBar

工具栏可以设置成固定的、浮动的等等,具体设置可以参考 Qt 文档。

前面我们说过,使用QAction::setStatusTip()可以设置该动作在状态栏上的提示文本。但我们现在把鼠标放在按钮上,是看不到这个提示文本的。原因很简单,我们没有添加一个状态栏。怎么添加呢?类似前面的QMainWindow::menuBar()QMainWindow有一个statusBar()函数。让我们把这个函数添加上去:

QToolBar *toolBar2 = addToolBar(tr("Tool Bar 2"));
toolBar2->addAction(openAction);

statusBar();

然后编译运行一下:

QMainWindow 状态栏

我们添加了一个孤零零的statuBar()显得不伦不类,但是,同前面的menuBar()的实现类似,这个函数会返回一个QStatusBar对象,如果没有则先创建再返回。

QStatusBar继承了QWidget,因此,我们可以将其它任意QWidget子类添加到状态栏,从而实现类似 Photoshop 窗口底部那种有比例显示、有网格开关的复杂状态栏。有关QStatusBar的更多信息,请参考 Qt 文档。

对于没有这些函数的QDialog或者QWidget怎么做呢?要记得,QToolBar以及QStatusBar都是QWidget的子类,因此我们就可以将其结合布局管理器添加到另外的QWidget上面。QLayout布局提供了setMenuBar()函数,可以方便的添加菜单栏。具体细节还是详见文档。

至此,我们已经将组成窗口元素介绍过一遍。结合这些元素以及布局管理,我们就应该可以实现一个简单的通用的窗口。当我们完成窗口布局之后,我们就可以考虑向其中添加功能。这就是我们后面章节的内容。

38 评论

gavin 2013年1月26日 - 12:18

既然单用 statusBar() 创建的状态栏可以显示 openAction 的 statusTip 那为什么之前的代码里面需要给这个状态栏添加动作呢?

QStatusBar *staBar = statusBar() ;
staBar->addAction(openAction);

回复
豆子 2013年1月27日 - 21:20

应该是不需要的;获取只是为了增加额外的动作。

回复
titi璇 2013年7月13日 - 15:57

😛 豆子老师,你好。关于状态栏的那个,有点疑问,我在你添加动作那一章代码中把
QStatusBar *staBar = statusBar() ;
staBar->addAction(openAction);
这句去掉,也没有加statusBar()这句,依旧可以显示状态。
请问为什么?是QT5新特性吗?

回复
豆子 2013年7月17日 - 15:45

Qt5 貌似没有增加这么个特性,可能是别的什么原因。

回复
hysteria 2013年11月30日 - 18:49

statusBar()是创建一个状态栏,在QT5.1.1去掉这个函数的调用也可显示状态栏,不同的是,我的MainWindow在生成的时候有ui->setupUi(this);这么一句,如果注释掉,会少很多东西,比如说,这个状态栏,窗口工作区等。

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

如果你使用的是 Qt Creator 默认生成的 GUI 界面,它会在 UI 文件中为你添加一个状态栏。既然你已经发现去掉了 ui->setupUi(this),状态栏就会消失,那么应该考虑可能是 statusBar() 函数作了修改,也可能是 ui->setupUi(this) 中为你添加了状态栏。

回复
逆、光 2014年7月19日 - 23:32

为什么我用addToolBar添加一个工具条后,就有了两个工具条,好像默认有一个工具条,怎么去掉默认的?
QToolBar *toolBar = addToolBar("标准");
toolBar->addAction(openAction);

回复
豆子 2014年7月20日 - 16:02

如果你使用的是 UI 文件,默认是由一个工具栏的。你可以在 UI 文件中将原有的工具栏移除;或者直接使用已有工具栏。

回复
xcamel 2014年8月15日 - 18:54

请问如果不是标准的快捷键,设置一般的快捷键应当怎么设置,比如“F7“?

回复
豆子 2014年8月16日 - 22:50

Qt 使用QKeySequence定义快捷键。这个类接受字符串或者Qt::Key类型,可以将所有支持的按键定义为快捷键。

回复
Sherry 2015年3月29日 - 12:46

请问豆子老师,如何给menuBar里的每个item设置不同的图片?

回复
豆子 2015年3月31日 - 10:32

item 的图标可以使用 QAction::setIcon 函数进行设置

回复
luodanoo 2015年5月7日 - 15:34

你好,在windows下Qt creator+QT5,怎么一调用openAction = new QAction();程序就异常结束,请问这是什么原因?

回复
luodanoo 2015年5月7日 - 17:55

你好,豆子老师。我是openAction = new QAction(tr("打开文件"),this),用的是中文,改成英文的就可以了。换回中文的,程序就直接异常结束。请问这个怎么解决?

回复
豆子 2015年6月3日 - 11:13

程序异常结束一般是以为内存问题

回复
philip 2015年6月2日 - 12:58

请问豆子老师,通过制定名称获取菜单可以么?
比如:
this->menuBar()->addMenu("&File");
this->menuBar()->addMenu("&Movie");
this->menuBar()->addMenu("&Music");

然后我想获取"&Movie",怎么办?

回复
豆子 2015年6月3日 - 09:32

是要通过菜单文本获取菜单?这种需求比较少的。一般都会把这个菜单项作为一个实例变量保存下来。如果确实需要通过菜单文字获取,可以使用 menuBar()->findChildren()获取所有菜单项,然后 foreach 遍历对比获得。

回复
philip 2015年6月3日 - 10:36

恩恩,收到,谢谢,一会试试去

回复
Bill 2015年7月31日 - 16:50

豆子老师,我把程序里面的所有&去掉也可以使用快捷键

回复
bill 2015年8月14日 - 16:57

豆子老师,在QML中直接定义ToolBar和ToolButton时也能创建多个工具栏吗?如何操作呢?

回复
Alain 2015年9月22日 - 20:52

您好,我在mac和ubuntun下加了菜单栏工具栏的代码,但是只能看到工具栏,一直看不到菜单栏。此外,QAction的第二个参数&Open设置了快捷键(快捷键是O?),且工具栏也设定了&File,这样没有设定icon的时候工具栏上显示的是File(F带下划线),那么&Open的快捷键这个设定有什么用呢?谢谢

回复
豆子 2015年9月23日 - 14:40

由于 mac 和 ubuntu 默认桌面环境的应用程序菜单栏和系统菜单栏是合二为一的,所以 Qt 也无法做到像 Windows 一样的分离。这是正常情况。

回复
Yann 2015年11月3日 - 11:31

豆子老师您好:
看您的作品有一段时间了,之前写了一个托盘,我想在托盘上显示当前状态。我就用了QWidgetAction。具体的做法是我重写了一个Qmenu类,然后在里面添加Action,由于上面的只需要显示当前状态,需要new一个Widget,(打算用QLabel显示内容。)Qwidget布局完成之后,将QWidgetAction的默认Widget设置成刚才new的那个Widget,完成之后在windows下都能正常显示,但是在Mac 下面就显示不出来,您能帮我解答一下吗?谢谢了 不胜感激。

回复
豆子 2015年11月4日 - 13:57

首先应该确定,Mac OS 系统是不是支持这种做法。由于 Mac 与 Windows 相差比较大,特别是托盘部分,所以很有可能是 Mac 系统并不支持这种显示。

回复
kael 2015年12月4日 - 09:41

楼主,是不是只有QmainWindow才能添加菜单栏,我试了一下QWidget不行

回复
豆子 2015年12月6日 - 19:21

菜单栏都可以添加,只不过是 QMainWIndow 默认设置了相关的布局管理器,提供了快捷函数。你可以在 QWidget 利用布局手动添加菜单。

回复
Joseph 2016年10月26日 - 11:33

#include
#include
#include
#include
#include
#include
#include "mainwindow.h"

void MainWindow::open() {
QMessageBox::information(this, tr("Information"), tr("Open"));
}

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent){
window()->resize(800,400);
openAction = new QAction(QIcon(":/images/im"), tr("open"), this);
openAction->setStatusTip("open a file");
connect(openAction, &QAction::triggered, this, &MainWindow::open);

QMenu *file = menuBar()->addMenu("&File");
file->addAction(openAction);
QMenu *file2 = menuBar()->addMenu("File");
file2->addAction(openAction);

QToolBar *toolBar = addToolBar ("&File");
toolBar->addAction(openAction);
QToolBar *toolBar2 = addToolBar("&File");
toolBar2->addAction(openAction);

statusBar();

}

MainWindow::~MainWindow(){}

豆老师你好,我这段代码在显示的时候没有出现menu,只出现工具栏,虽然设置了。而且还有一点不明就是如何让两个不同的toolbar对象指向不同的connect?

回复
Joseph 2016年10月26日 - 11:34

哦,对了1我这也是mac是不是与这个有关?
还有一个问题是设计模式下修改会改变源码的什么部分?

回复
豆子 2016年10月26日 - 22:08

Mac 系统本身就没有单独的菜单栏,它的菜单栏是与系统的整合在一起的。
设计模式不会改变源代码,而是生成一个独立的 UI 文件。这个文件用 XML 描述界面,之后,uic 会将其翻译成 C++ 代码,与其它代码一起编译

回复
liuyang 2018年7月29日 - 21:39

在:
connect(openAction, &QAction::triggered, this, MainWindow::open);
报错:
/home/xx/Desktop/Qt_ws/12_/mainwindow.cpp:18: error: no matching function for call to 'MainWindow::connect(QAction*&, void (QAction::*)(bool), MainWindow* const, )'
connect(openAction, &QAction::triggered, this, MainWindow::open);

^

回复
豆子 2018年8月4日 - 08:23

最后的 MainWindow::open 参数前面少了取址符号 &

回复
苹果 2020年1月9日 - 19:25

你好豆子老师,我想问下QToolBar* toolbar = addToolbar(tr("&file"));在创建Widget项目中显示错误error: use of undeclared identifier 'addToolbar'
在创建MainWindow项目中却没有,这两之间有什么区别吗?

回复
豆子 2020年1月13日 - 15:27

addToolbar() 是 QMainWindow 的一个函数。在 Widget 项目中,基类是 QWidget,所以没有这个函数

回复
chenchen 2020年2月5日 - 10:11

豆子先生为什么像我这样分步创建menuBar 为什么一定要加 this->? 谢谢!
QMenuBar * menuBar;
menuBar=this->menuBar();
QMenu *file=menuBar->addMenu(tr("&OPEN")); //OK

QMenuBar * menuBar;
menuBar=menuBar(); //去掉this->
QMenu *file=menuBar->addMenu(tr("&OPEN")); //NG

回复
陈国崇 2022年3月3日 - 15:37

可以不用this 改掉你创建的对象名就可以了 可能是因为对象名与函数名重名出错

回复
陈国崇 2022年3月3日 - 17:55

定义的对象名与函数名重名了,改对象名就可以了

回复
Vick 2021年2月25日 - 09:52

第一部分代码示例connect连接的槽函数没有取指针
&MainWindow::open
评论有人问了,不过还没修改,提醒下

回复
豆子 2021年2月27日 - 09:17

感谢提醒,现在已经修改过了

回复

发表评论

关于我

devbean

devbean

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

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