Qt窗⼝是通过QMainWindow类来实现的。 QMainWindow是⼀个为⽤⼾提供主窗⼝程序的类,继承⾃QWidget类,并且提供了⼀个预定义的 布局。QMainWindow包含⼀个菜单栏(menubar)、多个⼯具栏(toolbars)、多个浮动窗⼝(铆 接部件)(dockwidgets)、⼀个状态栏(statusbar)和⼀个中⼼部件(centralwidget),它是许多应 ⽤程序的基础,如⽂本编辑器,图⽚编辑器等。如下图为QMainwindow中各组件所处的位置:
1. 菜单栏
Qt 中的菜单栏是通过QMenuBar这个类来实现的。⼀个主窗⼝最多只有⼀个菜单栏。位于主窗⼝顶部、主窗⼝标题栏下⾯。 菜单栏中包含菜单.菜单中包含菜单项
菜单栏(QMenuBar)->菜单(QMenu)->菜单项(QAction)
1.1使用代码创建菜单结构:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 1. 先创建一个菜单栏//释放窗口时,该对象也会被释放QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);// 2. 创建菜单QMenu* menu1 = new QMenu("文件");QMenu* menu2 = new QMenu("编辑");QMenu* menu3 = new QMenu("视图");menuBar->addMenu(menu1);menuBar->addMenu(menu2);menuBar->addMenu(menu3);// 3. 给菜单添加菜单项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);// 4. 给 action 添加信号槽//点击菜单的时候,会处理响应connect(action1, &QAction::triggered, this, &MainWindow::handle);connect(action5, &QAction::triggered, this, &MainWindow::close);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::handle()
{qDebug() << "触发新建操作!";
}
执行效果如下:
1.2 给菜单配置快捷键
给菜单和菜单项设置快捷键,设置好的快捷键就可以搭配alt来进行使用了。
(文件(&F));通过给文本中添加&F这样的操作,就是添加了快捷键alt+F
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 创建菜单栏QMenuBar* menuBar = new QMenuBar();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);
}MainWindow::~MainWindow()
{delete ui;
}
1.3 给qaction创建快捷键
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);QMenu* menu1 = new QMenu("文件(&F)");QMenu* menu2 = new QMenu("视图(&V)");menuBar->addMenu(menu1);menuBar->addMenu(menu2);// 创建四个菜单项QAction* action1 = new QAction("action1 (&Q)");QAction* action2 = new QAction("action2 (&W)");QAction* action3 = new QAction("action3 (&E)");QAction* action4 = new QAction("action4 (&R)");menu1->addAction(action1);menu1->addAction(action2);menu2->addAction(action3);menu2->addAction(action4);// 不绑定槽函数, 通过快捷键选中也没啥反应~~connect(action1, &QAction::triggered, this, &MainWindow::handle1);connect(action2, &QAction::triggered, this, &MainWindow::handle2);connect(action3, &QAction::triggered, this, &MainWindow::handle3);connect(action4, &QAction::triggered, this, &MainWindow::handle4);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::handle1()
{qDebug() << "handle1";
}void MainWindow::handle2()
{qDebug() << "handle2";
}void MainWindow::handle3()
{qDebug() << "handle3";
}void MainWindow::handle4()
{qDebug() << "handle4";
}
1.4 菜单栏中添加子菜单
菜单栏->菜单->子菜单->子菜单->菜单项
通过Qmenu提供的addMenu给某个菜单添加子菜单;
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);QMenu* menuParent = new QMenu("父菜单");QMenu* menuChild = new QMenu("子菜单1");menuBar->addMenu(menuParent);menuParent->addMenu(menuChild);QAction* action1 = new QAction("菜单项1");QAction* action2 = new QAction("菜单项2");menuChild->addAction(action1);menuChild->addAction(action2);QMenu* menuChild2 = new QMenu("子菜单2");menuChild->addMenu(menuChild2);
}MainWindow::~MainWindow()
{delete ui;
}
执行效果如下所示:
1.5 添加分割线
菜单里菜单项特别多,就可以通过分割线,进行分组,QMenu中提供了addseparator这样的函数。
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QMenuBar* menuBar = new QMenuBar();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);
}
1.6 添加图标
使用qrc文件引入icon图片:
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// QMenuBar* menuBar = new QMenuBar();QMenuBar* menuBar = this->menuBar();this->setMenuBar(menuBar);QMenu* menu = new QMenu("菜单");menu->setIcon(QIcon(":/open.png"));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);
}MainWindow::~MainWindow()
{delete ui;
}
如果给QMenu设置图标,当前QMenu是长在QMenuBar上的,此时文本就不显示图标覆盖了文本。
QMenu是子菜单,图标和文本是都能显示的
1.7 内存泄漏问题
// QMenuBar* menuBar = new QMenuBar();
如果咱们创建的项目,没有勾选自动生成ui文件,此时上述代码是ok的
如果勾选了自动生成ui文件,上述代码则会引起内存泄露
因为Qt已经给你生成了一个QMenuBar了;之前程序自己已经创建好了一个QMenuBar
当设置新的QMenuBar进来的时候,就会导致旧的
QMenuBar脱离了Qt的对象树了.意味着后续就无法对这个对象进行释放了;上述程序如果窗口关闭,对象树释放,此时进程也就结束了.
进程结束,自然所有内存都回收给系统,上述内存泄露也不会造成影响
但是如果这样的代码是出现在一个多窗口的程序中:
如果涉及到窗口的频繁跳转切换(窗口的频繁创建销毁),上述内存泄露就会更严重一些所以为了防止内存泄漏,修改为如下代码:
QMenuBar* menuBar = this->menuBar();
1.如果QMenuBar已经存在,直接获取并返回
2.如果QMenuBar不存在,就先创建一个新的,再返回
如果是获取到已经存在的QMenuBar,这里的设置就是自己替换自己,
仍然在对象树上
2. ⼯具栏
更用QTooBar表示工具栏对象,一个窗口可以有多个工具栏,也可以没有。工具栏往往也可以手动移动位置。
Action如果出现在工具栏上,也会产生图标覆盖文本这样的情况。
如果一个QAction既是QMenu的子元素,又是QToolBar的子元素,释放的时候,只会释放一次,不会重复delete。
代码如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QToolBar>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 创建菜单栏QMenuBar* menuBar = this->menuBar();this->setMenuBar(menuBar);// 创建菜单QMenu* menu = new QMenu("文件");menuBar->addMenu(menu);// 工具栏是需要手动创建出来的. 自身不会自动创建.QToolBar* toolBar = new QToolBar();this->addToolBar(toolBar);// 创建两个菜单项QAction* action1 = new QAction("保存");QAction* action2 = new QAction("打开");// action1->setToolTip("点击这里保存文件");action1->setIcon(QIcon(":/save.png"));action2->setIcon(QIcon(":/open.png"));// 菜单项还可以放到菜单中menu->addAction(action1);menu->addAction(action2);// 菜单项放到工具栏中toolBar->addAction(action1);toolBar->addAction(action2);connect(action1, &QAction::triggered, this, &MainWindow::handle1);connect(action2, &QAction::triggered, this, &MainWindow::handle2);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::handle1()
{qDebug() << "handle1";
}void MainWindow::handle2()
{qDebug() << "handle2";
}
3.状态栏
状态栏是应⽤程序中输出简要信息的区域。。⼀般位于主窗⼝的最底部,⼀个窗⼝中最多只能有⼀个状 态栏。
代码如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QProgressBar>
#include <QPushButton>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 存在就获取, 不存在就创建QStatusBar* statusBar = this->statusBar();// 如果状态栏没有被创建, 这样的设置是必要的.// 如果状态栏已经在窗口中存在, 这样的设置其实意义不大, 但是也没副作用. 仍然保留.this->setStatusBar(statusBar);// 显示一个临时的信息.// statusBar->showMessage("这是一个状态消息");// 给状态栏中添加子控件QLabel* label = new QLabel("这是一个 QLabel");statusBar->addWidget(label);// QLabel* label2 = new QLabel("这个是另一个 QLabel");
// statusBar->addWidget(label2, 2);QProgressBar* progressBar = new QProgressBar();//这是进度条progressBar->setRange(0, 100);progressBar->setValue(50);statusBar->addWidget(progressBar);QPushButton* button = new QPushButton("按钮");statusBar->addPermanentWidget(button);
}MainWindow::~MainWindow()
{delete ui;
}
4. 浮动窗口
在Qt中是使用QDockWidget来实现的。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDockWidget>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 给主窗口添加一个子窗口.QDockWidget* dockWidget = new QDockWidget();// 使用 addDockWidget 方法, 把浮动窗口加入到子窗口中.this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);// 浮动窗口也是可以设置标题的.dockWidget->setWindowTitle("这是浮动窗口");// 给浮动窗口内部, 添加一些其他的控件.// 不能直接给这个浮动窗口添加子控件, 而是需要创建出一个单独的 QWidget, 把要添加的控件加入到 QWidget 中.// 然后再把这个 QWidget 设置到 dockWidget 中.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);
}MainWindow::~MainWindow()
{delete ui;
}
执行效果如下:
5. 对话框
Qt中使用QDialog类表示对话框,。Qt常 ⽤的内置对话框有:QFiledialog(⽂件对话框)、QColorDialog(颜⾊对话框)、QFontDialog (字体对话框)、QInputDialog(输⼊对话框)和QMessageBox(消息框)。
基于QDialog作为父类创建出来的程序窗口和之前通过QWidget创建出来的非常相似的。
实际开发中,往往不是直接在创建项目的时候继承自QDialog.而是在代码中,创建额外的类,让额外的类继承自QDialog。
主窗口,一般不会作为一个对话框。主窗口可以再产生出一些其他的对话框。
一个简单的例子:
主窗口中,通过点击按钮,弹出一个新的对话框。
QDialog其实也是QWidget的子类.QWidget的各种属性方法,QDialog也能使用。不同于界面上的其他控件.此处QDialog每次按下按钮,都会创建一个新的QDialog对象,并进行显示。每次点击都会创建新的对话框对象。
一个程序运行过程中,可以无数次点击这个按钮,进一步的就产生出无数个这样的对象了=>内存泄露
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{QDialog* dialog = new QDialog(this);dialog->setWindowTitle("对话框的标题");// 设置对话框的尺寸dialog->resize(400, 300);// 通过 show 方法就可以显示出对话框.dialog->show();// delete dialog;// 正确做法应该是把 delete 和关闭按钮的点击信号关联起来.// 在用户点击关闭的时候, 触发 delete.// Qt 为了让咱们写的方便, 直接给 QDialog 设置了一个属性, 可以通过设置属性, 完成上述效果.dialog->setAttribute(Qt::WA_DeleteOnClose);//通过设置属性,在进行关闭对话框操作的时候处罚delete内存的操作
}
5.1 自定义对话框
要想自定义对话框,就需要继承自QDialog创建类:
1)纯代码的方式来自定义QDialog界面
2)通过图形化的方式
5.2 model(bool)
模态 / 非模态
模态:弹出对话框的时候,此时用户无法操作父窗口.必须得完成对话框内部出的操作,关闭对话框之后。exec
非模态:弹出对话框的时候,用户可以操作父窗口。show
5.3 Qt内置对话框
Qt提供了多种可复⽤的对话框类型,即Qt标准对话框。Qt标准对话框全部继承于QDialog类。常⽤ 标准对话框如下:
消息对话框QMessageBox:
用来显示一个消息给用户,并且让用户进行一个简单的选择;
借助静态函数构造消息对话框
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}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";}
}
5.4 颜⾊对话框QColorDialog
颜⾊对话框的功能是允许⽤⼾选择颜⾊。继承⾃QDialog类。
void MainWindow::on_pushButton_clicked()
{
// QColorDialog* dialog = new QColorDialog(this);
// dialog->exec();
// delete dialog;// 函数的返回值就是用户选择的颜色.QColor color = QColorDialog::getColor(QColor(0, 255, 0), this, "选择颜色");qDebug() << color;
// getColor() 这个函数就能够弹出一个模态对话框.用户选择颜色之后,点击确定,
// 对话框关闭getcolor返回的值就是用户选择的颜色值!!
// 静态函数static.QMessageBoxwarning不必创建对话框对象,就可以直接使用// 可以基于用户选择的颜色, 修改窗口的背景色.// 可以通过 QSS 的方式设置背景色.
// QString style = "background-color: rgb(" + QString::number(color.red()) + ", " + QString::number(color.green())
// + ", " + QString::number(color.blue()) + ");";char style[1024] = { 0 };sprintf(style, "background-color: rgb(%d, %d, %d);", color.red(), color.green(), color.blue());this->setStyleSheet(style);
}
上述是对颜色框样式的设置。
5.5 ⽂件对话框QFileDialog
通过QFileDialog可以选择一个文件.能够获取到这个文件的路径打开文件/保存文件
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;
}
5.6 字体对话框QFontDialog
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();ui->pushButton->setFont(font);
5,7 输⼊对话框QInputDialog
让用户输入一个具体的数据,可以是整数,可以是浮点数,还可以是字符串.(以类似于下拉框)
ps:谢谢观看!!!