【Qt窗口】Qt窗口

文章目录

  • [1. 菜单栏](#1. 菜单栏)
    • [1.1 图形化方式创建](#1.1 图形化方式创建)
    • [1.2 代码方式创建](#1.2 代码方式创建)
  • [2. 工具栏](#2. 工具栏)
  • [3. 状态栏](#3. 状态栏)
  • [4. 浮动窗口](#4. 浮动窗口)
  • [5. 对话框](#5. 对话框)
    • [5.1 自定义对话框](#5.1 自定义对话框)
    • [5.2 Qt 内置对话框](#5.2 Qt 内置对话框)

前面学习的所有代码都是基于 QWidget(控件),QWidget 更多的是作为别的窗口的一个部分~~

Qt 窗口 是通过 QMainWindow类来实现的。

QMainWindow 是一个为用户提供主窗口程序的类,继承自 QWidget 类 ,并且提供了一个预定义的布局。QMainWindow 包含 **一个菜单栏(menu bar)、多个工具栏(tool bars)、多个浮动窗口(铆接部件)(dock widgets)、一个状态栏(status bar) 、一个 中心部件(central widget),**它是许多应用程序的基础,如文本编辑器,图片编辑器等。如下图为 QMainwindow 中 各组件所处的位置:


1. 菜单栏

Qt 中的菜单栏是通过 QMenuBar 这个类来实现的。一个主窗口最多只有一个菜单栏。位于主窗口顶部、主窗口标题栏下面。

菜单栏中包含菜单. 菜单中包含菜单项.

1.1 图形化方式创建

首先我们创建一个项目

注意:这次我们不再选择 QWidget 类,而是直接选择默认的 QMainWindow 类

项目创建好之后,双击ui文件,可以看到和之前Qwidget的不同

双击红框中的选项,就可以给菜单栏添加菜单了

我们先来直接运行看一下效果

在我们什么都不做的情况下的默认效果如上图所示

下面我们来添加一些菜单和菜单项

运行结果:

注意:我们在创建菜单项的时候会遇到一个小bug,就是不能将输入法切换为中文输入法,导致我们创建菜单项的时候不能输入中文。


1.2 代码方式创建

菜单栏的创建可以借助于 QMainWindow类 提供的 menuBar() 函数来实现。menubar()函数原型如下:

QMenuBar * menuBar() const

代码如下:

cpp 复制代码
    // 创建菜单栏
    QMenuBar* menubar = menuBar();
    // 将菜单栏放入窗口中
    this->setMenuBar(menubar);

或者在堆上动态创建:

cpp 复制代码
    // 创建菜单栏
    QMenuBar* menubar = new QMenuBar(this);
    // 将菜单栏放入窗口中
    this->setMenuBar(menubar);

创建菜单,并通过 QMenu 提供的 addMenu() 函数 来添加菜单。

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
//    // 创建菜单栏
//    QMenuBar* menubar = menuBar();
//    // 将菜单栏放入窗口中
//    this->setMenuBar(menubar);
    // 创建菜单栏
    QMenuBar* menubar = new QMenuBar(this);
    // 将菜单栏放入窗口中
    this->setMenuBar(menubar);
    
    QMenu* menu1 = new QMenu("文件");
    QMenu* menu2 = new QMenu("编辑");
    QMenu* menu3 = new QMenu("视图");
    menubar->addMenu(menu1);
    menubar->addMenu(menu2);
    menubar->addMenu(menu3);
    
    
}

在 Qt 中,并没有专门的菜单项类,可以通过 QAction 类,抽象出公共的动作。如在菜单中添加菜单项.

💡 QAction 可以给菜单栏使用 也可以给工具栏使用.

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

//    // 创建菜单栏
//    QMenuBar* menubar = menuBar();
//    // 将菜单栏放入窗口中
//    this->setMenuBar(menubar);
    // 创建菜单栏
    QMenuBar* menubar = new QMenuBar(this);
    // 将菜单栏放入窗口中
    this->setMenuBar(menubar);

    QMenu* menu1 = new QMenu("文件");
    QMenu* menu2 = new QMenu("编辑");
    QMenu* menu3 = new QMenu("视图");
    menubar->addMenu(menu1);
    menubar->addMenu(menu2);
    menubar->addMenu(menu3);

    QAction* action1 = new QAction("新建");
    QAction* action2 = new QAction("打开");
    QAction* action3 = new QAction("保存");
    QAction* action4 = new QAction("另存为");
    QAction* action5 = new QAction("退出");

    menu1->addAction(action1);
    menu1->addAction(action2);
    menu1->addAction(action3);
    menu1->addAction(action4);
    menu1->addAction(action5);

}

运行结果:

我们现在点击这些菜单项没有任何反应,如何让点击菜单项有反应呢?

可以使用connect来关联槽函数达到我们需要的效果

例如:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

//    // 创建菜单栏
//    QMenuBar* menubar = menuBar();
//    // 将菜单栏放入窗口中
//    this->setMenuBar(menubar);
    // 创建菜单栏
    QMenuBar* menubar = new QMenuBar(this);
    // 将菜单栏放入窗口中
    this->setMenuBar(menubar);

    QMenu* menu1 = new QMenu("文件");
    QMenu* menu2 = new QMenu("编辑");
    QMenu* menu3 = new QMenu("视图");
    menubar->addMenu(menu1);
    menubar->addMenu(menu2);
    menubar->addMenu(menu3);

    QAction* action1 = new QAction("新建");
    QAction* action2 = new QAction("打开");
    QAction* action3 = new QAction("保存");
    QAction* action4 = new QAction("另存为");
    QAction* action5 = new QAction("退出");

    menu1->addAction(action1);
    menu1->addAction(action2);
    menu1->addAction(action3);
    menu1->addAction(action4);
    menu1->addAction(action5);

    connect(action1, &QAction::triggered, this, &MainWindow::handle);
    connect(action5, &QAction::triggered, this, &MainWindow::close);
}


MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::handle()
{
    qDebug() << "触发新建操作!";
}

运行结果:

代码示例:给菜单设置快捷键

给菜单和菜单项设置快捷键

设置好的快捷键就可以搭配 alt 来进行使用了.

编写 mainwindow.cpp 代码:

  • 通过给文本中添加 &F 这样的操作,就是添加了快捷键 alt+F
cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    // 创建菜单栏
    QMenuBar* menubar = new QMenuBar(this);
    this->setMenuBar(menubar);
    // 创建菜单
    QMenu* menu1 = new QMenu("文件(&F)");
    QMenu* menu2 = new QMenu("编辑(&E)");
    QMenu* menu3 = new QMenu("视图(&V)");
    QMenu* menu4 = new QMenu("关于(&A)");
    menubar->addMenu(menu1);
    menubar->addMenu(menu2);
    menubar->addMenu(menu3);
    menubar->addMenu(menu4);
    //创建菜单项
    QAction* action1 = new QAction("菜单项1");
    QAction* action2 = new QAction("菜单项2");
    QAction* action3 = new QAction("菜单项3");
    QAction* action4 = new QAction("菜单项4");
    menu1->addAction(action1);
    menu2->addAction(action2);
    menu3->addAction(action3);
    menu4->addAction(action4);
}

运行结果:

& 这个符号并不会在界面上显示~~

上古时期,还没有图形界面的时候,文本编辑器都是靠类似风格的快捷键来操作的~~QShortCut 也可以实现类似的效果~~就是比这种方式麻烦点

代码示例:添加子菜单

QMenu 也提供了 addMenu,通过这个操作给某个菜单项添加子菜单~

编写 mainwindow.cpp 代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    QMenuBar* menubar = new QMenuBar(this);
    this->setMenuBar(menubar);
    
    QMenu* menuParent = new QMenu("父菜单");
    QMenu* menuChild = new QMenu("子菜单");
    menubar->addMenu(menuParent);
    menuParent->addMenu(menuChild);
    
    QAction* action1 = new QAction("菜单项1");
    QAction* action2 = new QAction("菜单项2");
    menuChild->addAction(action1);
    menuChild->addAction(action2);
}

运行结果:

可以看到鼠标悬停在上面就能展开子菜单~~

代码示例:在菜单项之间添加分割线

菜单里菜单项特别多,就可以通过分割线,进行分组~~

QMenu 中提供了 addSeparator 这样的函数~~

编写 mainwindow.cpp 代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    QMenuBar* menubar = new QMenuBar(this);
    this->setMenuBar(menubar);
    
    QMenu* menu = new QMenu("菜单");
    menubar->addMenu(menu);
    
    QAction* action1 = new QAction("菜单项1");
    QAction* action2 = new QAction("菜单项2");
    menu->addAction(action1);
    menu->addSeparator();
    menu->addAction(action2);
}

运行结果;

代码示例:给菜单项添加图标

这里我们提前准备好图片

把图片导入到我们的项目中(qrc管理)

编写 mainwindow.cpp 代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    QMenuBar* menubar = new QMenuBar(this);
    this->setMenuBar(menubar);
    
    QMenu* menu = new QMenu("菜单");
    menubar->addMenu(menu);
    
    QAction* action1 = new QAction("菜单项1");
    action1->setIcon(QIcon(":/open.png"));
    QAction* action2 = new QAction("菜单项2");
    action2->setIcon(QIcon(":/save.png"));
    menu->addAction(action1);
    menu->addAction(action2);
}

运行结果:

如果给 QMenu 设置图标,

当前 QMenu 是长在 QMenuBar 上的, 此时文本就不显示,也就是图标覆盖了文本

但是如果 QMenu 是子菜单~~,图标和文本是都能显示的.

关于创建菜单栏的注意事项:

如果咱们创建的项目。没有勾选自动生成 ui 文件,此时上述代码是 ok 的,如果勾选了自动生成ui文件,上述代码则会引起内存泄露.

因为 Qt 已经给你生成了一个 QMenuBar 了

之前程序自己已经创建好了一个 QMenuBar,当设置新的 QMenuBar 进来的时候,就会导致l日的QMenuBar 脱离了Qt 的对象树了.意味着后续就无法对这个对象进行释放了~~

上述程序如果窗口关闭,对象树释放,此时进程也就结束了.进程结束,自然所有内存都回收给系统~~,上述内存泄露也不会造成影响

但是如果这样的代码是出现在一个多窗口的程序中~如果涉及到窗口的频繁跳转切换(窗口的频繁创建销毁),上述内存泄露就会更严重一些.

但是实际上由于现在的计算机内存都比较充裕上述内存泄露都还好~

服务器程序相比于客户端程序更害怕内存泄露~~

  1. 服务器要处理很多请求,每个请求泄露一点,请求积累下来就会泄露很多
  2. 服务器要 7*24 小时运行.

当然,即使如此,还是期望把代码写的更规范一些~~

cpp 复制代码
    // 创建菜单栏
    QMenuBar* menubar = menuBar();
    // 将菜单栏放入窗口中
    this->setMenuBar(menubar);

通过menuBar函数来获取菜单栏:

  1. 如果 QMenuBar 已经存在,直接获取并返回.
  2. 如果 QMenuBar 不存在,就先创建一个新的, 再返回.

如果是获取到已经存在的QMenuBar,这里的设置就是自己替换自己~还是自己~~仍然在对象树上~~


2. 工具栏

工具栏是应用程序中集成各种功能实现快捷键使用的一个区域。可以有多个,也可以没有,它并不是应用程序中必须存在的组件。它是一个可移动的组件,它的元素可以是各种窗口组件,它的元素通常以图标按钮方式存在。如下图为工具栏的示意图:

使用 QToolBar 表示工具栏对象~一个窗口可以有多个工具栏,也可以没有~

工具栏往往也可以手动移动位置~~

编写代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QToolBar* toolbar = new QToolBar(this);
    this->addToolBar(toolbar);
    // 创建菜单项
    QAction* action1 = new QAction("保存");
    QAction* action2 = new QAction("打开");
    // 菜单项放到工具栏中
    toolbar->addAction(action1);
    toolbar->addAction(action2);
    
}

添加菜单栏,使用的是setMenuBar------菜单栏只能有一个,重复设置,新的替换旧的.(set 就包含了"替换")

添加工具栏, 使用的是 addToolBar------工具栏,可以有多个,重复设置,就会出现多个工具栏不包含"替换"

运行结果:

典型的工具栏,这里展示的一般是图标,而不是文本~~

我们再编辑一下代码,这里同样使用qrc来管理

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QToolBar* toolbar = new QToolBar(this);
    this->addToolBar(toolbar);
    // 创建菜单项
    QAction* action1 = new QAction("保存");
    QAction* action2 = new QAction("打开");
    action1->setIcon(QIcon(":/save.png"));
    action2->setIcon(QIcon(":/open.png"));
    // 菜单项放到工具栏中
    toolbar->addAction(action1);
    toolbar->addAction(action2);

}

运行结果:

QAction 如果出现在工具栏上,也会产生 图标 覆盖文本 这样的情况~~但是鼠标悬停上去的时候,就会显示出一段提示信息~~另外也可以手动设置这里的tooITip

工具栏往往也是和菜单栏搭配使用的~~工具栏中的 QAction 也可以出现在菜单中~~

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 创建菜单栏
    QMenuBar* menubar = menuBar();
    // 创建菜单
    QMenu* menu = new QMenu("文件");
    menubar->addMenu(menu);
    // 创建工具栏
    QToolBar* toolbar = new QToolBar(this);
    this->addToolBar(toolbar);
    // 创建菜单项
    QAction* action1 = new QAction("保存");
    QAction* action2 = new QAction("打开");
    action1->setIcon(QIcon(":/save.png"));
    action2->setIcon(QIcon(":/open.png"));
    // 菜单项还可以放到菜单中
    menu->addAction(action1);
    menu->addAction(action2);
    // 菜单项放到工具栏中
    toolbar->addAction(action1);
    toolbar->addAction(action2);

}

运行结果:

如果一个 QAction 既是 QMenu 的子元素,又是 QToolBar 的子元素,释放的时候,是否会重复 delete ??

答案是只会释放一次,不会重复delete

代码示例:创建多个工具栏

编写代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    QToolBar* toolbar1 = new QToolBar(this);
    QToolBar* toolbar2 = new QToolBar(this);
    this->addToolBar(toolbar1);
    this->addToolBar(toolbar2);
    
    QAction* action1 = new QAction("动作1");
    QAction* action2 = new QAction("动作2");
    QAction* action3 = new QAction("动作3");
    QAction* action4 = new QAction("动作4");
    toolbar1->addAction(action1);
    toolbar1->addAction(action2);
    toolbar2->addAction(action3);
    toolbar2->addAction(action4);
}

运行结果:

如果把工具栏拖出来放到窗口的任意位置,称之为"浮动"状态

  1. 可以设置工具栏出现的初始位置 (上下左右...)

MainWindow 提供了 addToolBar

在创建工具栏的同时,也可以设工具栏的位置,其默认位置是在窗口的最上面;如上述代码,默认在最上面显示。

修改代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QToolBar* toolbar1 = new QToolBar(this);
    QToolBar* toolbar2 = new QToolBar(this);
    this->addToolBar(toolbar1);
    this->addToolBar(Qt::LeftToolBarArea, toolbar2);

    QAction* action1 = new QAction("动作1");
    QAction* action2 = new QAction("动作2");
    QAction* action3 = new QAction("动作3");
    QAction* action4 = new QAction("动作4");
    toolbar1->addAction(action1);
    toolbar1->addAction(action2);
    toolbar2->addAction(action3);
    toolbar2->addAction(action4);
}

运行结果:

  1. 可以设置工具栏允许停放到哪些边缘~~

工具栏停靠位置的设置是通过 QToolBar类 提供的 setAllowedAreas()函数 来设置。

工具栏允许停靠的区域由 QToolBar类 提供的 allowAreas()函数 决定,其中可以设置的位置包括:

  • Qt::LeftToolBarArea 停靠在左侧
  • Qt::RightToolBarArea 停靠在右侧
  • Qt::TopToolBarArea 停靠在顶部
  • Qt::BottomToolBarArea 停靠在底部
  • Qt::AllToolBarAreas 以上四个位置都可停靠

修改代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QToolBar* toolbar1 = new QToolBar(this);
    QToolBar* toolbar2 = new QToolBar(this);
    this->addToolBar(toolbar1);
    this->addToolBar(Qt::LeftToolBarArea, toolbar2);
    
    // 只允许停靠在左侧或者右侧
    toolbar2->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);

    QAction* action1 = new QAction("动作1");
    QAction* action2 = new QAction("动作2");
    QAction* action3 = new QAction("动作3");
    QAction* action4 = new QAction("动作4");
    toolbar1->addAction(action1);
    toolbar1->addAction(action2);
    toolbar2->addAction(action3);
    toolbar2->addAction(action4);
}

运行结果:

可以看到只能处于左右两侧,也可以处于浮动状态

说明:

在创建工具栏的同时指定其停靠的位置,指的是程序运行时工具栏默认所在的位置;而使用setAllowedAreas()函数设置停靠位置,指的是工具栏允许其所能停靠的位置。

  1. 可以设置工具栏是否允许浮动

工具栏的浮动属性可以通过 QToolBar类 提供的 setFloatable()函数 来设置。

修改代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QToolBar* toolbar1 = new QToolBar(this);
    QToolBar* toolbar2 = new QToolBar(this);
    this->addToolBar(toolbar1);
    this->addToolBar(Qt::LeftToolBarArea, toolbar2);

    // 只允许停靠在左侧或者右侧
    toolbar2->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);

    // 设置不允许浮动
    toolbar2->setFloatable(false);
    
    QAction* action1 = new QAction("动作1");
    QAction* action2 = new QAction("动作2");
    QAction* action3 = new QAction("动作3");
    QAction* action4 = new QAction("动作4");
    toolbar1->addAction(action1);
    toolbar1->addAction(action2);
    toolbar2->addAction(action3);
    toolbar2->addAction(action4);
}

运行结果:

可以看到现在不能浮动在任意位置了

  1. 可以设置工具栏是否可以移动~~

设置工具栏的移动属性可以通过 QToolBar类 提供的 setMovable()函数 来设置。

修改代码:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QToolBar* toolbar1 = new QToolBar(this);
    QToolBar* toolbar2 = new QToolBar(this);
    this->addToolBar(toolbar1);
    this->addToolBar(Qt::LeftToolBarArea, toolbar2);

    // 只允许停靠在左侧或者右侧
    toolbar2->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);

    // 设置不允许浮动
    toolbar2->setFloatable(false);
    
    // 设置不允许移动
    toolbar2->setMovable(false);

    QAction* action1 = new QAction("动作1");
    QAction* action2 = new QAction("动作2");
    QAction* action3 = new QAction("动作3");
    QAction* action4 = new QAction("动作4");
    toolbar1->addAction(action1);
    toolbar1->addAction(action2);
    toolbar2->addAction(action3);
    toolbar2->addAction(action4);
}

运行结果:

可以看到选中 toolbar2 时的光标不会再变成十字形状,只能移动 toolbar1


3. 状态栏

状态栏是应用程序中输出简要信息的区域。一般位于主窗口的最底部,一个窗口中最多只能有一个状态栏。在 Qt 中,状态栏是通过 QStatusBar类 来实现的。 在状态栏中可以显示的消息类型有:

  • 实时消息:如当前程序状态
  • 永久消息:如程序版本号,机构名称
  • 进度消息:如进度条提示,百分百提示

显示实时消息:

通过 showMessage 可以在状态栏中显示一个文本.

此时这个文本存在的时间可以自定义,timeout 参数是一个单位为 ms 的时间.如果 timeout 为 0(不填),消息就会持久存在~~

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    QStatusBar* statusbar = new QStatusBar(this);
    this->setStatusBar(statusbar);
    // 显示一个临时的信息.
    statusbar->showMessage("这是一个状态消息", 3000);
}

运行结果:

还可以在状态栏中添加控件

例如:

添加一个标签,显示永久消息

在添加控件到状态栏中时有两个接口,上面的接口是从左往右添加,下面的接口是从右往左添加

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QStatusBar* statusbar = new QStatusBar(this);
    this->setStatusBar(statusbar);
    // 显示一个临时的信息.
    //statusbar->showMessage("这是一个状态消息", 3000);
    
    QLabel* label = new QLabel("这是一个QLable");
    statusbar->addWidget(label);
}

运行结果:

还可以添加其他控件

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QStatusBar* statusbar = new QStatusBar(this);
    this->setStatusBar(statusbar);
    // 显示一个临时的信息.
    //statusbar->showMessage("这是一个状态消息", 3000);

    QLabel* label = new QLabel("这是一个QLable");
    statusbar->addWidget(label);
    
    QProgressBar* progressbar = new QProgressBar(this);
    progressbar->setRange(0, 100);
    progressbar->setValue(50);
    statusbar->addWidget(progressbar);
    
    QPushButton* button = new QPushButton("按钮", this);
    statusbar->addPermanentWidget(button);
}

运行结果:


4. 浮动窗口

在 Qt 中,浮动窗口也称之为铆接部件。浮动窗口是通过 QDockWidget类 来实现浮动的功能。浮动窗口一般是位于核心部件的周围,可以有多个

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 给主窗口添加一个子窗口
    QDockWidget* dockwidget = new QDockWidget(this);
    // 使用 addDockWidget 方法, 把浮动窗口加入到子窗口中.
    this->addDockWidget(Qt::LeftDockWidgetArea, dockwidget);
    
    // 浮动窗口也是可以设置标题的.
    dockwidget->setWindowTitle("这是浮动窗口");
}

运行结果:

给浮动窗口内部, 添加一些其他的控件,不能直接给这个浮动窗口添加子控件, 而是需要创建出一个单独的 QWidget, 把要添加的控件加入到 QWidget 中,然后再把这个 QWidget 设置到 dockWidget 中.

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 给主窗口添加一个子窗口
    QDockWidget* dockwidget = new QDockWidget(this);
    // 使用 addDockWidget 方法, 把浮动窗口加入到子窗口中.
    this->addDockWidget(Qt::LeftDockWidgetArea, dockwidget);

    // 浮动窗口也是可以设置标题的.
    dockwidget->setWindowTitle("这是浮动窗口");

    QWidget* container = new QWidget();
    dockwidget->setWidget(container);

    // 创建布局管理器, 把布局管理器设置到 QWidget 中
    QVBoxLayout* layout = new QVBoxLayout;
    container->setLayout(layout);

    // 创建其他控件添加到 layout 中.
    QLabel* label = new QLabel("这是一个 QLabel");
    QPushButton* button = new QPushButton("这是按钮");
    layout->addWidget(label);
    layout->addWidget(button);

    // 设置浮动窗口允许停靠的位置
    dockwidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea);
}

可以通过 QDockWidget类 中提供 setAllowedAreas() 函数设置其允许停靠的位置。其中可以设置允许停靠的位置有:

  • Qt::LeftDockWidgetArea 停靠在左侧
  • Qt::RightDockWidgetArea 停靠在右侧
  • Qt::TopDockWidgetArea 停靠在顶部
  • Qt::BottomDockWidgetArea 停靠在底部
  • Qt::AllDockWidgetAreas 以上四个位置都可停靠

运行结果:


5. 对话框

对话框是 GUI 程序中不可或缺的组成部分。一些不适合在主窗口实现的功能组件可以设置在对话框中。对话框通常是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。Qt常用的内置对话框有:QFiledialog(文件对话框)、QColorDialog(颜色对话框)、QFontDialog(字体对话框)、QInputDialog (输入对话框)和 QMessageBox(消息框)

5.1 自定义对话框

Qt中使用QDialog类表示对话框, 针对一个已有的项目,也可以创建一些类,继承自 QDialog 实现咱们自定义的对话框~~总体来说,基于 QDialog 作为父类创建出来的程序窗口和之前通过 QWidget 创建出来的非常相似的.

实际开发中,更多的情况,往往不是直接在创建项目的时候继承自 QDialog.而是在代码中,创建额外的类,让额外的类继承自 QDialog.

主窗口,一般不会作为一个对话框,主窗口可以再产生出一些其他的对话框~~

代码示例:主窗口中,通过点击按钮,弹出一个新的对话框~~

QDialog 其实也是 QWidget 的子类. QWidget 的各种属性方法,QDialog 也能使用.

添加槽函数:

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QDialog* dialog = new QDialog(this);
    dialog->setWindowTitle("对话框的标题");
    dialog->resize(400, 300);
    dialog->show();
}

运行结果:

注意!! 不同于界面上的其他控件,此处 QDialog 每次按下按钮,都会创建一个新的 QDialog 对象,并进行显示.每次点击都会创建新的对话框对象!!!

一个程序运行过程中,可以无数次点击这个按钮,进一步的就产生出无数个这样的对象了~~=>内存泄露~~

可是我们不是把对话框添加到对象树中了吗

那应该要怎么delete呢?

如果我们直接在槽函数结尾加上delete去释放dialog对象可不可以呢

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QDialog* dialog = new QDialog(this);
    dialog->setWindowTitle("对话框的标题");
    dialog->resize(400, 300);
    dialog->show();
    
    delete dialog;
}

运行结果:

很明显我们刚把对话框show展示出来就delete掉,就会出现一闪而过的效果

正确的做法,应该是让用户点击对话框关闭按钮的时候,再来触发这里的delete 操作~~

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QDialog* dialog = new QDialog(this);
    dialog->setWindowTitle("对话框的标题");
    dialog->resize(400, 300);
    dialog->show();

    //delete dialog;
    // Qt 为了让咱们写的方便, 直接给 QDialog 设置了一个属性, 可以通过设置属性, 完成上述效果.
    dialog->setAttribute(Qt::WA_DeleteOnClose);
}

只要给 dialog 设置上上述属性,此时就会在关闭的时候自动进行 delete,Qt 内置的功能.

自定义对话框界面:

要想自定义对话框,就需要继承自QDialog创建类~~

  1. 纯代码的方式来自定义 QDialog 界面
  2. 通过图形化的方式

纯代码方式:

编写ui文件

添加槽函数

这里我们就不再使用 QDialog 类了,而是手动创建一个新的类继承 QDialog

点击Choose后,填写类名和继承的类

点击下一步

直接点击完成

这里我们需要在头文件中包含QDialog

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    Dialog* dialog = new Dialog();
    dialog->resize(400, 300);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
}

实现自定义类

cpp 复制代码
Dialog::Dialog()
{
    // 创建出一些控件, 加入到 Dialog 中. (以 Dialog 作为父窗口)
    QVBoxLayout* layout = new QVBoxLayout();
    this->setLayout(layout);
    
    QLabel* label = new QLabel("这是一个对话框", this);
    QPushButton* button = new QPushButton("关闭", this);
    layout->addWidget(label);
    layout->addWidget(button);
    
    connect(button, &QPushButton::clicked, this, &Dialog::handle);
}

void Dialog::handle()
{
    this->close();
}

运行结果:

图形化方式:

还是一样先在ui界面添加一个按钮

添加槽函数

此时我们通过图形化的方式自定义Dialog类

关键操作,是创建出一个新的 ui 文件出来.

这个操作创建出一个ui文件以及对应的类~~

这里我们可以选择模板,直接选择没有按钮的对话框并点击下一步

这里类名也已经给我们定义好了,直接使用默认的

点击完成即可

此时我们就可以看到新增了一个对话框的ui文件

编辑对话框的ui文件

拖拽一个标签和按钮

实现槽函数:

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    Dialog* dialog = new Dialog();
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
}

编写对话框中按钮的槽函数

cpp 复制代码
void Dialog::on_pushButton_clicked()
{
    this->close();
}

运行结果:

对话框分为 模态对话框非模态对话框

模态:弹出对话框的时候,此时用户无法操作父窗口,必须得完成对话框内部出的操作,关闭对话框之后.用于特别关键的场合,用户必须要做出决策!!!

非模态:弹出对话框的时候,用户可以操作父窗口,不是特别关键的场景~~

前面写的几个代码,都是"非模态"对话框~

如何产生模态对话框??

把 show 换成 exec 即可.

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    Dialog* dialog = new Dialog();
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    //dialog->show();
    dialog->exec();
}

运行结果:


5.2 Qt 内置对话框

Qt 提供了多种可复用的对话框类型,即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog类。常用标准对话框如下:

消息对话框 QMessageBox

消息对话框是应用程序中最常用的界面元素。消息对话框主要用于为用户提示重要信息,强制用户进行选择操作。

QMessageBox类 中定义了静态成员函数,可以直接调用创建不同风格的消息对话框,其中包括:

Question 用于正常操作过程中的提问
Information 用于报告正常运行信息
Warning 用于报告非关键错误
Critical 用于报告严重错误

其对应的函数原型如下:

代码示例

先拖拽一个按钮

添加槽函数

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QMessageBox* messageBox = new QMessageBox(this);
    messageBox->setWindowTitle("对话框窗口标题");
    messageBox->setText("这是对话框的文本");
    messageBox->setIcon(QMessageBox::Warning);
    messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Save | QMessageBox::Cancel);
    
    // 非模态的弹框. QMessageBox 使用场景更多的是模态的.
    // messageBox->show();
    // 弹出模态对话框, 当对话框处于弹出状态的时候, 代码就会在 exec 这里阻塞. 一直到对话框被关闭.
    messageBox->exec();
    messageBox->setAttribute(Qt::WA_DeleteOnClose);
}

这些按钮都是Qt内置的,其中可以设置的按钮的类型如下:

运行结果:

还可以使用自定义的按钮

ButtonRole是一个枚举类型,用于标识按钮在对话框中的角色,例如:

  • AcceptRole:表示"接受"操作(通常对应"确定""是"等确认性按钮)。
  • RejectRole:表示"拒绝"操作(通常对应"取消""否"等否定性按钮)。
  • DestructiveRole:表示"破坏性"操作(如"删除""退出",通常会有警告提示)。
  • ActionRole:表示执行某个动作(如"保存""打印")。
  • HelpRole:表示提供帮助(如"帮助"按钮)。
  • YesRole/ NoRole:明确对应"是"/"否"按钮。
  • InvalidRole:无效角色(一般不使用)。
cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QMessageBox* messageBox = new QMessageBox(this);
    messageBox->setWindowTitle("对话框窗口标题");
    messageBox->setText("这是对话框的文本");
    messageBox->setIcon(QMessageBox::Warning);
    // 标准按钮中, 根本就没法进行信号槽的连接. (按钮是 QMessageBox 自己生成的)
    // messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Save | QMessageBox::Cancel);
    
    QPushButton* button = new QPushButton("按钮", messageBox);
    messageBox->addButton(button, QMessageBox::AcceptRole);

    // 非模态的弹框. QMessageBox 使用场景更多的是模态的.
    // messageBox->show();
    // 弹出模态对话框, 当对话框处于弹出状态的时候, 代码就会在 exec 这里阻塞. 一直到对话框被关闭.
    messageBox->exec();
    messageBox->setAttribute(Qt::WA_DeleteOnClose);
}

运行结果:

还可以通过 connect 连接信号槽, 来针对当前点击的按钮进行一些相关操作.、

但是标准按钮中, 根本就没法进行信号槽的连接. (按钮是 QMessageBox 自己生成的)

这个时候就需要在用户点击按钮, 使对话框关闭之后, 此时就要通过 exec 的返回值, 来知道用户点击的是哪个按钮, 从而执行一些对应的逻辑了.

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QMessageBox* messageBox = new QMessageBox(this);
    messageBox->setWindowTitle("对话框窗口标题");
    messageBox->setText("这是对话框的文本");
    messageBox->setIcon(QMessageBox::Warning);
    // 标准按钮中, 根本就没法进行信号槽的连接. (按钮是 QMessageBox 自己生成的)
    messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Save | QMessageBox::Cancel);

//    QPushButton* button = new QPushButton("按钮", messageBox);
//    messageBox->addButton(button, QMessageBox::AcceptRole);

    // 非模态的弹框. QMessageBox 使用场景更多的是模态的.
    // messageBox->show();
    // 弹出模态对话框, 当对话框处于弹出状态的时候, 代码就会在 exec 这里阻塞. 一直到对话框被关闭.
    int result = messageBox->exec();
    if (result == QMessageBox::Ok) 
    {
        qDebug() << "OK";
    } 
    else if (result == QMessageBox::Save) 
    {
        qDebug() << "Save";
    } 
    else if (result == QMessageBox::Cancel) 
    {
        qDebug() << "Cancel";
    }
    messageBox->setAttribute(Qt::WA_DeleteOnClose);
}

运算结果:

还有一种方法,可以不用手动创建消息对话框 QMessageBox,可以直接调用Qt内置的接口来达到类似的效果

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    int result = QMessageBox::information(this, "对话框标题", "对话框文本", QMessageBox::Ok | QMessageBox::Cancel);
    if (result == QMessageBox::Ok) 
    {
        qDebug() << "Ok";
    } 
    else if (result == QMessageBox::Cancel) 
    {
        qDebug() << "Cancel";
    }
}

运行结果:

颜色对话框 QColorDialog

颜色对话框的功能是允许用户选择颜色。继承自 QDialog 类。颜色对话框如下图示:

常用方法介绍:

  1. QColorDialog (QWidget *parent = nullptr)创建对象的同时设置父对象

  2. QColorDialog(const QColor &initial, QWidget *parent = nullptr) 创建对象的同时通过 QColor 对象设置默认颜色和父对象

  3. void setCurrentColor(const QColor &color) 设置当前颜色对话框

  4. QColor currentColor() const 获取当前颜色对话框

  5. QColor getColor(const QColor &initial = Qt::white, QWidget *parent = nullptr, const QString &title = QString(), QColorDialog::ColorDialogOptions options = ColorDialogOptions()) 打开颜色选择对话框,并返回一个QColor对象

参数说明:

  • initial:设置默认颜色
  • parent:设置父对象
  • title:设置对话框标题
  • options:设置选项
  1. void open(QObject *receiver, const char *member) 打开颜色对话框

代码示例

编辑ui文件

拖拽一个按钮控件

编辑槽函数

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    // 函数的返回值就是用户选择的颜色.
    QColor color = QColorDialog::getColor(QColor(0, 255, 0), this, "选择颜色");

    // 可以基于用户选择的颜色, 修改窗口的背景色.
    // 可以通过 QSS 的方式设置背景色.
    QString style = "background-color: rgb(" + QString::number(color.red()) + ", " + 
            QString::number(color.green())+ ", " + QString::number(color.blue()) + ");";
    this->setStyleSheet(style);
}

运行结果:

文件对话框 QFileDialog

文件对话框用于应用程序中需要打开一个外部文件或需要将当前内容存储到指定的外部文件。

常用方法介绍:

  1. 打开文件(一次只能打开一个文件)

QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())

  1. 打开多个文件(一次可以打开多个文件)

QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())

  1. 保存文件

QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())

参数说明:

参数1:parent 父亲

参数2:caption 对话框标题

参数3:dir 默认打开的路径

参数4:filter 文件过滤器

代码示例:

编辑ui文件

编写槽函数

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this);
    qDebug() << filePath;
}

void MainWindow::on_pushButton_2_clicked()
{
    QString filePath = QFileDialog::getSaveFileName(this);
    qDebug() << filePath;
}

运行结果:

此处的打开/保存这里的功能都是需要额外去实现的~~并不是说直接一按保存就真的保存了~~

后面我们会专门介绍 Qt 针对文件的操作~~

字体对话框 QFontDialog

Qt 中提供了预定义的字体对话框类 QFontDialog,用于提供选择字体的对话框部件。

代码示例:

编辑ui文件

编辑槽函数

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    bool ok = false;
    QFont font = QFontDialog::getFont(&ok);
    qDebug() << "ok = " << ok;
    qDebug() << font;
    qDebug() << font.family();
    qDebug() << font.pointSize();
    qDebug() << font.bold();
    qDebug() << font.italic();
}

运行结果:

输入对话框 QInputDialog

Qt 中提供了预定义的输入对话框类:QInputDialog,用于进行临时数据输入的场合。

常用方法介绍:

  1. 双精度浮点型输入数据对话框

double getDouble (QWidget *parent, const QString &title, const QString &label, double value = 0, double min = -2147483647, double max = 2147483647, int decimals = 1, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());

  1. 整型输入数据对话框

int getInt (QWidget *parent, const QString &title, const QString &label, int value = 0, int min = -2147483647, int max = 2147483647, int step = 1, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());

  1. 选择条目型输入数据框

QString getItem (QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current = 0, bool editable = true, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints = Qt::ImhNone) ;

参数说明:

  • parent:父亲
  • title:对话框标题
  • label:对话框标签
  • items:可供选择的条目

代码示例:

编辑ui文件

编写槽函数

cpp 复制代码
void MainWindow::on_pushButton_clicked()
{
    int result = QInputDialog::getInt(this, "整数输入对话框", "请输入一个整数: ");
    qDebug() << result;
}

void MainWindow::on_pushButton_2_clicked()
{
    double result = QInputDialog::getDouble(this, "浮点数输入对话框", "请输入一个浮点数: ");
    qDebug() << result;
}

void MainWindow::on_pushButton_3_clicked()
{
    QStringList items;
    items.push_back("111");
    items.push_back("222");
    items.push_back("333");
    items.push_back("444");
    QString item = QInputDialog::getItem(this, "条目输入对话框", "请输入条目: ", items);
    qDebug() << item;
}

运行结果:

相关推荐
炸膛坦客2 小时前
单片机/C/C++八股:(十七)C++ 中指针和引用的区别
c语言·开发语言·c++
行者..................2 小时前
第1课:搭建 Linux 驱动与 Qt 开发基础环境
linux·运维·qt·mpsoc
小王不爱笑13210 小时前
IO 模型
开发语言·python
知我Deja_Vu10 小时前
【避坑指南】ConcurrentHashMap 并发计数优化实战
java·开发语言·python
AI+程序员在路上10 小时前
CANopen 协议:介绍、调试命令与应用
linux·c语言·开发语言·网络
2401_8318249610 小时前
基于C++的区块链实现
开发语言·c++·算法
m0_5180194811 小时前
C++与机器学习框架
开发语言·c++·算法
ZTLJQ11 小时前
深入理解逻辑回归:从数学原理到实战应用
开发语言·python·机器学习
qq_4176950511 小时前
C++中的代理模式高级应用
开发语言·c++·算法