QMainWindow

QMainWindow是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个停靠部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget),是许多应用程序的基础,如文本编辑器,图片编辑器等。

image-20240604111400709

菜单栏

一个主窗口最多只有一个菜单栏。位于主窗口顶部、主窗口标题栏下面。

  1. 通过QMainWindow类的menubar()函数获取主窗口菜单栏指针,如果当前窗口没有菜单栏,该函数会自动创建一个。

    QMenuBar *menuBar = w.menuBar();// 获取主窗口的菜单栏指针
    
  2. 创建菜单,调用QMenu的成员函数addMenu来添加菜单

    QAction* addMenu(QMenu * menu);
    QMenu* addMenu(const QString & title);
    QMenu* addMenu(const QIcon & icon, const QString & title);
    
    MainWindow w;
    QMenuBar *menubar = w.menuBar();// 获取主窗口的菜单栏指针
    QMenu *menu = menubar->addMenu("menu");// 添加主菜单
    QMenu *submenu = new QMenu("submenu");// 添加子菜单
    menu->addMenu(submenu);
    QAction *newAction = submenu->addAction("new action"); // 添加子菜单项
    w.show();
    

    image-20240604120433923鼠标摸住子菜单的时候就会弹出子菜单选项

  3. 创建菜单项,调用QMenu的成员函数addAction来添加菜单项

    QAction* activeAction() const;
    QAction* addAction(const QString & text);
    QAction* addAction(const QIcon & icon, const QString & text);
    QAction* addAction(const QString & text, const QObject * receiver,
                       const char * member, const QKeySequence & shortcut = 0);
    QAction* addAction(const QIcon & icon, const QString & text, 
                       const QObject * receiver, const char * member, 
                       const QKeySequence & shortcut = 0);
    
    1. QAction* activeAction() const;
      • 这个函数返回当前活动的动作(Action)。
      • 活动的动作是用户最后选择的动作,或者在程序中通过编程方式设置的动作。
    2. QAction* addAction(const QString & text);
      • 这个函数用于向菜单或工具栏添加一个文本动作。
      • text 参数是要显示在动作上的文本。
      • 返回添加的动作对象的指针。
    3. QAction* addAction(const QIcon & icon, const QString & text);
      • 这个函数用于向菜单或工具栏添加一个带图标和文本的动作。
      • icon 参数是要显示在动作上的图标。
      • text 参数是要显示在动作上的文本。
      • 返回添加的动作对象的指针。
    4. QAction* addAction(const QString & text, const QObject * receiver, const char * member, const QKeySequence & shortcut = 0);
      • 这个函数用于向菜单或工具栏添加一个文本动作,并与指定的对象的槽函数关联。
      • text 参数是要显示在动作上的文本。
      • receiver 参数是槽函数的接收者对象。
      • member 参数是槽函数的名称。
      • shortcut 参数是可选的键盘快捷键。
      • 返回添加的动作对象的指针。
    5. QAction* addAction(const QIcon & icon, const QString & text, const QObject * receiver, const char * member, const QKeySequence & shortcut = 0);
      • 这个函数用于向菜单或工具栏添加一个带图标和文本的动作,并与指定的对象的槽函数关联。
      • icon 参数是要显示在动作上的图标。
      • text 参数是要显示在动作上的文本。
      • receiver 参数是槽函数的接收者对象。
      • member 参数是槽函数的名称。
      • shortcut 参数是可选的键盘快捷键。
      • 返回添加的动作对象的指针。
#include "mainwindow.h"
#include <QApplication>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QDebug>
#include <QToolBar>
#include <QObject>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QMainWindow w;
    QMenuBar *menubar = w.menuBar();// 获取主窗口的菜单栏指针
    QMenu *menu = menubar->addMenu("menu");// 添加主菜单
    QMenu *submenu = new QMenu("submenu");// 添加子菜单
    menu->addMenu(submenu);
    QAction *Action1 = submenu->addAction("action:kiss");
    QAction *Action2 = submenu->addAction("action:hug");
    qDebug() << "Active action:" << submenu->activeAction();  // 打印活动的动作
    // 添加动作到工具栏
    QToolBar* toolBar = w.addToolBar("Toolbar");
    QAction* Action3 = toolBar->addAction("action:sleep");
    QAction* Action4 = toolBar->addAction("action:play");
    QObject::connect(Action1,&QAction::triggered,[&](){
         qDebug() << "kiss triggered";
    });
    QObject::connect(Action2,&QAction::triggered,[&](){
        qDebug() << "hug triggered";
    });
    QObject::connect(Action3,&QAction::triggered,[&](){
        qDebug() << "sleep triggered";
    });
    QObject::connect(Action4,&QAction::triggered,[&](){
        qDebug() << "play triggered";
    });
    w.show();
    return a.exec();
}

这段代码里我们使用了子菜单栏和工具栏两种方式解释我们的action以及打印动作的用法。

image-20240604123844138

image-20240604123855167

通过点击各种行为,然后经过[槽函数](Qt学习第三篇(信号槽函数的连接) - ivanlee717 - 博客园 (cnblogs.com))的连接,可以在终端看到这些行为。

image-20240604123955086

Qt 并没有专门的菜单项类,只是使用一个QAction类,抽象出公共的动作。当我们把QAction对象添加到菜单,就显示成一个菜单项,添加到工具栏,就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按钮、点击快捷键来激活这个动作。

工具栏

主窗口的工具栏上可以有多个工具条,通常采用一个菜单对应一个工具条的的方式,也可根据需要进行工具条的划分。

  1. 调用QMainWindowd对象的成员函数addToolBar(),该函数每次调用都会创建一个新的工具栏,并且返回该工具栏的指针。

  2. 插入属于工具条的项,这时工具条上添加项也是用QAction。通过QToolBar类的addAction函数添加。

  3. 工具条是一个可移动的窗口,它的停靠区域由QToolBar的allowAreas决定,包括(以下值可以通过查帮助文档allowAreas来索引到):

    Qt::LeftToolBarArea 停靠在左侧

    Qt::RightToolBarArea 停靠在右侧

    Qt::TopToolBarArea 停靠在顶部

    Qt::BottomToolBarArea 停靠在底部

    Qt::AllToolBarAreas 以上四个位置都可停靠

    toolBar->addAction(new QAction(QIcon(":/images/newfile.png"), "New", &w));
    toolBar->addAction(new QAction(QIcon(":/images/open.png"), "Open", &w));
    toolBar->addAction(new QAction(QIcon(":/images/1.png"), "Save", &w));
    
    // 设置工具栏可以停靠的所有区域
    toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea|Qt::BottomToolBarArea);
    

    这里我们允许了工具栏移动到左右和底部,初始的位置如下:image-20240604200803264

    但是我们可以根据红箭头指向的位置进行拖动,image-20240604200828679

    image-20240604200843447

    image-20240604200859594

    此外,我们看到工具栏里有一个是图形图标,但是其他都是字符,这就用到了我们资源文件的配置。

    Qt的资源系统(Resource System)把图像文件的路径添加到.qrc文件中。.qrc文件是Qt用来组织和管理项目中静态资源(如图像、样式表、翻译文件等)的一种方式。资源文件允许你以一种平台无关的方式引用项目内的文件,并且在编译时,这些资源会被编译进应用程序的二进制文件中,便于部署和访问。

    具体操作步骤如之前所述,简要回顾如下:

    1. 创建或打开 .qrc 文件:在Qt Creator中,通过“文件”>“新建文件或项目”>“Qt”>“Qt资源文件”来创建一个新的资源文件,或者直接在项目目录中手动创建一个.qrc文件。

    2. .qrc 文件中添加图像:使用Qt Creator的资源编辑器,右键点击资源文件树,选择“添加”>“文件”,然后浏览并选择你的图像文件(如1.png),将其添加到资源集合中。你可以为资源指定一个逻辑路径,例如/images/1.png,其中/images是一个自定义的前缀,用于组织资源。

    3. 在代码中引用资源:一旦图像被添加到资源文件,你就可以通过资源的URL(如":/images/1.png")在代码中引用它了。如果没有找到具体路径,则只显示后续的字符串

      具体的如下图所示:

image-20240604195924055

image-20240604195946269

使用setFloatable(trueOrFalse)函数来设定工具栏可否浮动image-20240604201503363这样就代表可以把工具栏单独拉出整个窗口位置,false反之。

使用setMoveable(trueOrFalse)函数设定工具栏的可移动性:image-20240604201558061我们设置为false之后发现原来左侧的一排可移动的点消失了,setMoveable(false)//工具条不可移动, 只能停靠在初始化的位置上。

状态栏

一个QMainWindow的程序最多只有一个状态栏。QMainWindow中可以有多个的部件都使用add…名字的函数,而只有一个的部件,就直接使用获取部件的函数,如menuBar。同理状态栏也提供了一个获取状态栏的函数statusBar(),没有就自动创建一个并返回状态栏的指针。

w.statusBar()->showMessage("regina");
w.statusBar()->showMessage("ivanlee",3000);//3秒消失
//  添加一个永久显示的组件
QLabel *permenentLabel = new QLabel("permenent status");
w.statusBar()->addPermanentWidget(permenentLabel);
QProgressBar *progressBar = new QProgressBar;
w.statusBar()->addWidget(progressBar);

image-20240604224907983

停靠部件(也称为铆接部件、浮动窗口)

停靠部件 QDockWidget,也称浮动窗口,可以有多个。

image-20240604225826218

QDockWidget提供了dock Widget的概念,也称为工具选项板或实用程序窗口。停靠窗口是放置在QMainWindow中心小部件周围的停靠小部件区域中的辅助窗口。停靠窗口可以在其当前区域内移动,移动到新区域,并由最终用户浮动(例如,取消停靠)。QDockWidget API允许程序员限制dock小部件移动、浮动和关闭的能力,以及它们可以放置的区域。

// 创建停靠部件1,包含一个按钮
QDockWidget *dock1 = new QDockWidget("停靠部件1", &w);
QWidget *widgetContent1 = new QWidget(dock1);
QPushButton *button1 = new QPushButton("按钮1", widgetContent1);
QVBoxLayout *layout1 = new QVBoxLayout(widgetContent1);
layout1->addWidget(button1);
dock1->setWidget(widgetContent1);

// 创建停靠部件2,也包含一个按钮
QDockWidget *dock2 = new QDockWidget("停靠部件2", &w);
QWidget *widgetContent2 = new QWidget(dock2);
QPushButton *button2 = new QPushButton("按钮2", widgetContent2);
QVBoxLayout *layout2 = new QVBoxLayout(widgetContent2);
layout2->addWidget(button2);
dock2->setWidget(widgetContent2);

// 添加停靠部件到主窗口,并设定默认停靠位置
w.addDockWidget(Qt::LeftDockWidgetArea, dock1);
w.addDockWidget(Qt::RightDockWidgetArea, dock2);

// 设定停靠部件允许停靠的范围
dock1->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea);
dock2->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);

image-20240604230225527

image-20240604230239701

ui

image-20240605094955926

image-20240605095205160在这些地方可以进行添加和删除部件。

使用UI文件创建界面很轻松很便捷,他的原理就是每次我们保存UI文件的时候,QtCreator就自动帮我们将UI文件翻译成C++的图形界面创建代码。可以通过以下步骤查看代码

到工程编译目录,一般就是工程同级目录下会生成另一个编译目录,会找到一个带ui_前缀跟ui文件同名的.h文件,这就是代码

image-20240605110313495

image-20240605110521461

代码内容为:image-20240605110623344

在项目MainWindow的构造函数中会调用这个函数来初始化窗口,其实这里边就是初始化我们的各个控件。image-20240605110741974

ui使用信号槽

在UI编辑界面中使用信号和槽很方便,比如,拖出一个Button到窗口上,右键这个button,选择转到槽:image-20240605111130565

此时会出现这个控件(QPushButton)可以连接的各个信号,我们可以根据具体需求选中信号来创建一个连接这个信号的槽函数:image-20240605111210170

以click(bool)信号为例,创建了一个槽函数。这个槽函数是QtCreator自动帮我们创建的,而且也使用生成C++代码的方式帮我们做好了连接,我们可以直接在这个函数体内实现功能就行。很方便,比使用Lambda表达式还方便。image-20240605111331495

可以使用动作编辑器旁边的信号槽编辑器,里边也可以添加信号和槽的连接,比如添加PushButton的clicked信号和radioButton槽的连接:image-20240605111750193

按住F4键就可以看到相互的关系

image-20240605111837764