目录
认识
Qt 窗⼝ 是通过 QMainWindow 来实现的:
- QMainWindow 是⼀个为用户提供主窗⼝程序的类,继承⾃ QWidget 类,并且提供了⼀个预定义的布局
- QMainWindow 包含 ⼀个菜单栏(menu bar)、多个⼯具栏(tool bars)、多个浮动窗⼝(dock widgets)、⼀个状态栏(status bar) 和⼀个中心部件(central widget)
如下图为 QMainwindow 中 各组件所处的位置

菜单栏
Qt 中的菜单栏是通过 QMenuBar 这个类来实现的。⼀个主窗⼝最多只有⼀个菜单栏。位于主窗⼝顶部、主窗⼝标题栏下⾯;菜单栏中包含菜单,菜单中包含菜单项
为什么菜单项不命名成 QMenuItem 呢? 主要是要与工具栏进行兼容:工具栏本质上也是菜单栏的"快捷方式":点击菜单项是一次动作,点击工具栏上的选项也是一次动作,Qt 使用 QAction 就是把这二者进行了统一
创建 Qt项目进行使用,此时选择的就不是 QWidget,则是 QMainWinodw

ui 上进行添加

设置后运行,查看运行结果

使用代码进行实现
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏
QMenuBar* bar = new QMenuBar(this);
// 创建菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("视图");
bar->addMenu(menu1);
bar->addMenu(menu2);
// 创建菜单栏
QAction* action1 = new QAction("新建");
QAction* action2 = new QAction("保存");
QAction* action3 = new QAction("另存为");
menu1->addAction(action1);
menu1->addAction(action2);
menu1->addAction(action3);
// 关联信号
connect(action1,&QAction::triggered,this,&MainWindow::hadnler);
}

- 给菜单和菜单项设置快捷键
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏
QMenuBar* bar = new QMenuBar();
this->setMenuBar(bar);
// 创建菜单
QMenu* menu1 = new QMenu("文件 (&F)");
QMenu* menu2 = new QMenu("视图 (&V)");
bar->addMenu(menu1);
bar->addMenu(menu2);
// 创建菜单栏
QAction* action1 = new QAction("新建 (&C)");
QAction* action2 = new QAction("保存 (&S)");
QAction* action3 = new QAction("另存为 (&A)");
QAction* action4 = new QAction("打开 (&O)");
menu1->addAction(action1);
menu1->addAction(action2);
menu1->addAction(action3);
menu2->addAction(action4);
// 关联信号
connect(action1,&QAction::triggered,this,&MainWindow::hadnler);
}

- 菜单除了可以添加菜单项,还可以添加子菜单,子菜单中再添加菜单项(嵌套菜单)
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏
QMenuBar* bar = new QMenuBar();
this->setMenuBar(bar);
// 创建菜单
QMenu* Parent = new QMenu("菜单");
QMenu* Child = new QMenu("子菜单");
bar->addMenu(Parent);
Parent->addMenu(Child);
// 创建菜单项
QAction* action = new QAction("菜单项");
Child->addAction(action);
}

- 菜单项添加分割线
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏
QMenuBar* bar = new QMenuBar();
this->setMenuBar(bar);
QMenu* menu = new QMenu("菜单");
bar->addMenu(menu);
// 创建菜单项
QAction* action1 = new QAction("菜单项1");
QAction* action2 = new QAction("菜单项2");
menu->addAction(action1);
// 添加分割线
menu->addSeparator();
menu->addAction(action2);
}

- 添加图标
使用前面的 QIcon 和 qrc 机制来完成
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏
QMenuBar* bar = new QMenuBar();
this->setMenuBar(bar);
// 创建菜单
QMenu* menu = new QMenu("菜单");
menu->setIcon(QIcon(":/1.png"));
bar->addMenu(menu);
// 创建子菜单
QMenu* menu_child = new QMenu("子菜单");
menu_child->setIcon(QIcon(":/1.png"));
menu->addMenu(menu_child);
// 创建菜单项
QAction* action = new QAction("菜单项");
action->setIcon(QIcon(":/1.png"));
menu_child->addAction(action);
}
菜单栏中的菜单添加图标后不显示文本,而子菜单和菜单项都显示了,原始是 Qt 考虑到菜单栏可能有很多,内容放不下,添加图标后把文本给覆盖了

上面创建项目中我们勾选了自动生成 ui 文件

所以会给我们自动生成一个菜单栏

如果按照之前的代码,就会把 menubar 进行替换,同时把它从对象树上移除,所以每次启动关闭窗口就有内存泄漏,所以要想优雅地,正确写出代码来,用它自动生成的反而更好

工具栏
工具栏就没有自动创建一说了,所以说需要自己创建了
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QToolBar* tool = new QToolBar();
this->addToolBar(tool);
// 设置图标后文件就以提示词呈现
QAction* action1 = new QAction("工具栏1");
QAction* action2 = new QAction("工具类2");
// 也可以自行设置提示词
action1->setToolTip("这是一个提示词");
// 一般工具栏是以图标展示
action1->setIcon(QIcon(":/1.png"));
action2->setIcon(QIcon(":/1.png"));
tool->addAction(action1);
tool->addAction(action2);
// 工具栏的内容一般在菜单栏存在
QMenuBar* menu_bar = ui->menubar;
QMenu * menu = new QMenu("菜单");
menu_bar->addMenu(menu);
menu->addAction(action1);
menu->addAction(action2);
}
一个 Action 的父节点既是 QToolBar 也是 QMenu,对象树释放时会不会释放两次? Qt考虑到这方面的问题,所有会跟随最近是否的父节点一同释放,之后就不会释放了
- 工具栏的位置
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QToolBar* tool1 = new QToolBar();
QToolBar* tool2 = new QToolBar();
// 添加工具类可以拖动到左右两测
tool2->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
// 添加工具栏
this->addToolBar(tool1);
// 添加工具栏的起始位置
this->addToolBar(Qt::LeftToolBarArea,tool2);
QAction* action1 = new QAction("工具1");
QAction* action2 = new QAction("工具2");
tool1->addAction(action1);
tool2->addAction(action2);
}


状态栏
一般在窗口最下方,使用 QStatusBar 实现,一般提示
- 实时消息:如当前程序状态
- 永久消息:如程序版本号,机构名称
- 进度消息:如进度条提⽰,百分百提示
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 有创建返回,没有创建则会新创建
QStatusBar* status = this->statusBar();
// 如果有创建该代码不起效果
this->setStatusBar(status);
// 设置的时间内显示提示信息
//status->showMessage("hello qt",3000);
QLabel * label1 = new QLabel("这是 label1 提示词");
status->addWidget(label1);
QLabel * label2 = new QLabel("这是 label2 提示词");
status->addPermanentWidget(label2);
}

QDockWidget
创建浮动窗口,也就是在主窗口中创建子窗口
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDockWidget* dock = new QDockWidget();
// 添加的同时需要设置浮动窗口的位置
this->addDockWidget(Qt::RightDockWidgetArea,dock);
dock->setWindowTitle("这是一个 dock 窗口");
// dock 只能添加一个 QWidget,所以先创建一个 QWidget 容器
QWidget* contain = new QWidget();
// 再创建一个布局管理器
QVBoxLayout* layout = new QVBoxLayout();
// 往 layout 添加组件
QLabel* label = new QLabel("这是 label 组件");
QPushButton* botton = new QPushButton("按钮");
layout->addWidget(label);
layout->addWidget(botton);
// 依次进行添加
contain->setLayout(layout);
dock->setWidget(contain);
}

对话框
对话框是 GUI 程序中不可或缺的组成部分。⼀些不适合在主窗⼝实现的功能组件可以设置在对话框中。对话框通常是⼀个顶层窗⼝,出现在程序最上层,⽤于实现短期任务或简洁的用户交互
常见的对话框(QDialog 子类)
- QFiledialog(⽂件对话框)
- QColorDialog(颜⾊对话框)
- QFontDialog(字体对话框)
- QInputDialog(输⼊对话框)
- QMessageBox(消息框)
案例1:使用按钮点击,弹出一个简单的对话框
cpp
void MainWindow::on_pushButton_clicked()
{
QDialog* dialog = new QDialog(this);
// dialog 是 QWidget 的子类,QWidget的方法它都能使用
dialog->resize(600,700);
dialog->show();
dialog->setAttribute(Qt::WA_DeleteOnClose);
}

QDialog 并没有再这之后 delete,它要等到 QMainWindow delete 后才 delete,但如果 QDialog 很大,用户多点击按钮创建就会造成内存泄漏,解决方法是用户点击 X 的信号进行关联实现释放 QDialog 的函数,但其实还有更简单的做法:QDialog 中设置属性 Qt::WA_DeleteOnClose 完成自动释放的工作
cpp
dialog->setAttribute(Qt::WA_DeleteOnClose);
案例2:自己来创建对话框类,如果在该类中添加控件比如实现按钮来关闭该对话框
- 使用代码:Qt 中创建类

填写相关信息

cpp
//Dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
// 使用 Dialog 继承 QDialog
class Dialog:public QDialog
{
Q_OBJECT
public:
Dialog(QWidget* parent = nullptr);
};
#endif // DIALOG_H
//Dialog.cpp
Dialog::Dialog(QWidget* parent)
:QDialog(parent)
{
// 可以在这里给对话框新增控件
QVBoxLayout* layout = new QVBoxLayout();
// 添加组件使用 QVBoxLayout 管理
QLabel * label = new QLabel("这是一个关闭对话框的按钮");
QPushButton* button = new QPushButton("关闭");
layout->addWidget(label);
layout->addWidget(button);
// 再添加到 Dialog 中
this->setLayout(layout);
connect(button,&QPushButton::clicked,this,[&](){
this->close();
});
}
案例1将 QDialog 替换为 Dialog

- 使用 ui:创建设计师界面类

设置相关信息

完成后会多出三个文件,自己在 dialog.ui 下,以 ui 方式增加组件

刚好生成的 dialog 类与前面类名相同,增加控件完成就可以运行查看结果

模态与非模态
对话框有模态与非模态的概念:模态就是创建对话框后,不能操作父类窗口的各种控件;而非模态则可以,我们上面创建的对话框就是非模态

要想变成模态只需要改一行代码即可
cpp
//dialog->show();
dialog->exec(); // 变成模态
除了 QDialog 外,还通过它为父类设计出了很多具有各种属性的对话框
QMessageBox
消息对话框,提示用户选择哪个操作去执行,通常是以模态对话框来使用; QMessageBox 提供了各种静态成员函数设置图标

cpp
void MainWindow::on_pushButton_clicked()
{
QMessageBox* message = new QMessageBox(this);
message->resize(300,300);
message->setWindowTitle("这是一个消息对话框");
message->setText("按下任意按钮");
message->setIcon(QMessageBox::Question);
// 按钮可以使用宏自动生成,如果不设置默认给OK按钮
message->setStandardButtons(QMessageBox::Ok | QMessageBox::No | QMessageBox::Cancel);
// 返回用户按下的按钮
int button_result = message->exec();
if(button_result == QMessageBox::Ok)
qDebug()<<"Ok";
// 因为 exec 方法执行时代码阻塞在函数中,所有这里也可以自行使用 delete 进行是否
delete message;
//message->setAttribute(Qt::WA_DeleteOnClose);
}

自行添加按钮则还需要传入按钮角色,也就是提供的各种宏

cpp
// 也可以手动设置 -> conncet 关联槽函数
QPushButton* botton = new QPushButton("确认");
message->addButton(botton,QMessageBox::AcceptRole);
- 也可以一键式设计对话框窗口
cpp
void MainWindow::on_pushButton_clicked()
{
// 大写Warning是设置图标
int result = QMessageBox::warning(this,"这是一个消息对话框","选择按钮",QMessageBox::Ok | QMessageBox::No);
if(result == QMessageBox::Ok)
qDebug()<<"OK";
else
qDebug()<<"No";
}
QColorDialog
颜色对话框,Qt 中的颜色对话框创建完就可以使用了,相当于已经内置了
案例:获取用户选择的颜色设置主窗口背景色
cpp
void MainWindow::on_pushButton_clicked()
{
// QColorDialog* color = new QColorDialog(this);
// color->exec();
// 也是可以一键式创建
QColor color = QColorDialog::getColor(Qt::blue,this,"颜色对话框");
char buff[1024] = {0};
sprintf(buff,"background-color: rgb(%d,%d,%d);",color.red(),color.green(),color.blue());
// 设置用户选择的背景色
this->setStyleSheet(buff);
}

QFileDialog
文件对话框,⽤于应⽤程序中需要打开⼀个外部⽂件或需要将当前内容存储到指定的文件
案例:实现两个按钮:打开文件和保存文件(此处并没有去具体实现功能)
cpp
void MainWindow::on_pushButton_clicked()
{
QString path = QFileDialog::getOpenFileName(this);
qDebug()<<path;
}
void MainWindow::on_pushButton_2_clicked()
{
QString path = QFileDialog::getSaveFileName(this);
qDebug()<<path;
}
QFontDialog
字体对话框,用户选择字体相关信息后可以对某个空间上的文本进行设置
案例:点击按钮出现字体对话框,通过它来设置按钮文本
cpp
void MainWindow::on_pushButton_clicked()
{
bool ok = false;
QFont font = QFontDialog::getFont(&ok,this);
qDebug()<<font.family()<<' '<<font.pointSize();
ui->pushButton->setFont(font);
}

QInputDialog
输入对话框,让用户根据提示输入对应类型的数据,比如:int,float,QString
案例:按钮触发输入对话框,获取用户输入的数据打印在终端下
cpp
void MainWindow::on_pushButton_clicked()
{
// int result = QInputDialog::getInt(this,"整数输入框","输入一个整数:");
// qDebug()<<result;
// double result = QInputDialog::getDouble(this,"整数输入框","输入一个整数:");
// qDebug()<<result;
// 相当于 vector<string>
QStringList list;
list.push_back("111");
list.push_back("222");
QString result = QInputDialog::getItem(this,"条目选择","选择或者输入",list);
qDebug()<<result;
}
以上便是全部内容,有问题欢迎在评论区指正,感谢观看!