Qt 窗口是通过 QMainWindow类 来实现的。
QMainWindow 是一个为用户提供主窗口程序的类,继承自 QWidget 类,并且提供了一个预定义的布局。QMainWindow 包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个浮动窗口(铆接部件)(dock widgets)、⼀个状态栏(status bar) 和⼀个 中心部件(central widget),它是许多应用程序的基础,如文本编辑器,图片编辑器等。如下图为 QMainwindow 中 各组件所处的位置:
Qt 中的菜单栏是通过 QMenuBar 这个类来实现的。⼀个主窗口最多只有⼀个菜单栏。位于主窗口顶部、主窗⼝标题栏下面。
菜单栏中包含菜单. 菜单中包含菜单项.
菜单栏的创建可以借助于 QMainWindow类 提供的 menuBar() 函数来实现。创建菜单,并通过 QMenu 提供的 addMenu() 函数 来添加菜单。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏
// QMenuBar* menubar = 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 可以给菜单栏使⽤, 也可以给⼯具栏使⽤.
修改 mainwindow.cpp :
// 添加菜单项
QAction* action1 = new QAction("save");
QAction* action2 = new QAction("quit");
QAction* action3 = new QAction("open");
menu1->addAction(action1);
menu1->addAction(action2);
menu1->addAction(action3);
在菜单项之间可以添加分割线。分割线如下图所⽰,添加分割线是通过 QMenu 类 提供的 addSeparator() 函数来实现:
menu1->addAction(action1);
menu1->addSeparator();
menu1->addAction(action2);
menu1->addSeparator();
menu1->addAction(action3);
在窗⼝上创建⼀个菜单栏,在菜单栏中添加⼀些菜单,在某⼀个菜单中添加⼀些菜单项。
(1)在 “mainwindow.cpp” ⽂件中创建菜单和中央控件
创建⼀个菜单栏, ⼀个菜单.
两个菜单项: 保存, 加载
创建⼀个 QTextEdit 作为窗⼝的中央控件.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置标题
this->setWindowTitle("记事本");
// 创建菜单栏
QMenuBar* menubar = new QMenuBar(this);
this->setMenuBar(menubar);
// 创建菜单
QMenu* menu = new QMenu("文件");
menubar->addMenu(menu);
// 创建菜单项
QAction* action1 = new QAction("保存");
QAction* action2 = new QAction("加载");
menu->addAction(action1);
menu->addAction(action2);
// 创建中央控件,添加 edit 为成员变量,方便后面使用
edit = new QTextEdit(this);
this->setCentralWidget(edit);
edit->setPlaceholderText("此处编写文本内容");
}
(2)给 action 添加⼀些动作
// 连接信号槽, 点击 action 时触发⼀定的效果.
connect(action1, &QAction::triggered, this, &MainWindow::save);
connect(action2, &QAction::triggered, this, &MainWindow::load);
实现这两个槽函数:
getSaveFileName ⽤于保存⽂件的场景. 此时的对话框可以输⼊⽂件名. getOpenFileName ⽤于打开⽂件的场景. 此时的对话框可以获取到⿏标选择的⽂件名.
搭配 C++ 标准库的⽂件操作实现⽂件读写.
void MainWindow::save()
{
// 弹出对话框,选择写入文件的路径
QFileDialog* dialog = new QFileDialog(this);
QString fileName = dialog->getSaveFileName(this, "保存文件", "D:/QtProject");
// 写入文件
std::ofstream file(fileName.toStdString().c_str());
if(!file.is_open()){
qDebug() << "文件保存失败";
return;
}
const QString& text = edit->toPlainText();
file << text.toStdString();
file.close();
}
void MainWindow::load()
{
QFileDialog* dialog = new QFileDialog(this);
QString fileName = dialog->getOpenFileName(this, "加载文件", "D:/QtProject");
// 读取文件
std::ifstream file(fileName.toStdString().c_str());
if(!file.is_open()){
qDebug() << "文件加载失败";
return;
}
std::string content;
std::string line;
while(std::getline(file, line)){
content += line;
content += "\n";
}
file.close();
// 显示到界面上
QString text = QString::fromStdString(content);
edit->setPlainText(text);
}
⼯具栏是应⽤程序中集成各种功能实现快捷键使⽤的⼀个区域。可以有多个,也可以没有,它并不是应⽤程序中必须存在的组件。它是⼀个可移动的组件,它的元素可以是各种窗⼝组件,它的元素通常以图标按钮的⽅式存在。如下图为⼯具栏的⽰意图:
调⽤ QMainWindow类 的 addToolBar() 函数来创建⼯具栏,每增加⼀个⼯具栏都需要调⽤⼀次该函数。
如添加两个工具栏:
QToolBar* toolbar1 = new QToolBar(this);
QToolBar* toolbar2 = new QToolBar(this);
this->addToolBar(toolbar1);
this->addToolBar(toolbar2);
⼯具栏停靠位置的设置有两种⽅式。⼀种是在创建⼯具栏的同时指定停靠的位置,另⼀种是通过 QToolBar类提供的 setAllowedAreas()函数 来设置。
⽅式⼀:创建⼯具栏的同时指定其停靠的位置。
在创建⼯具栏的同时,也可以设置⼯具栏的位置,其默认位置是在窗⼝的最上⾯;如上述代码,默认在最上⾯显⽰。⼯具栏允许停靠的区域由 QToolBar类 提供的 allowAreas()函数 决定,其中可以设置的位置包括:
示例:
QToolBar* toolbar1 = new QToolBar(this);
QToolBar* toolbar2 = new QToolBar(this);
this->addToolBar(Qt::LeftToolBarArea, toolbar1);
this->addToolBar(Qt::RightToolBarArea, toolbar2);
⽅式⼆:使⽤ QToolBar类 提供的 setAllowedAreas()函数 设置停靠位置。如下⽰例:
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(Qt::LeftToolBarArea, toolbar1);
// this->addToolBar(Qt::RightToolBarArea, toolbar2);
this->addToolBar(toolbar1);
this->addToolBar(toolbar2);
// 只允许在左侧停靠
toolbar1->setAllowedAreas(Qt::LeftToolBarArea);
// 只允许在右侧停靠
toolbar2->setAllowedAreas(Qt::RightToolBarArea);
}
⼯具栏的浮动属性可以通过 QToolBar 类 提供的 setFloatable() 函数 来设置。setFloatable() 函数原型为:
void setFloatable (bool floatable)
参数:
true:浮动
false:不浮动
示例:
toolbar1->setFloatable(true);
toolbar2->setFloatable(false);
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
resize(800, 600);
QToolBar* toolBar = new QToolBar(this);
// 设置工具栏的位置,默认是在窗口的上面,此处设置在左侧
addToolBar(Qt::LeftToolBarArea, toolBar);
// 设置工具栏的停靠位置,设置工具栏只允许在左右停靠
toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
// 设置工具栏的浮动属性
toolBar->setFloatable(false);
// 设置工具栏的移动(总开关)
toolBar->setMovable(false);
// 设置工具栏内容
QAction* openAction = new QAction("open", this);
QAction* newAction = new QAction("new", this);
toolBar->addAction(openAction);
toolBar->addSeparator();
toolBar->addAction(newAction);
// 工具栏中也可以添加控件
QPushButton* button = new QPushButton("保存", this);
toolBar->addSeparator();
toolBar->addWidget(button);
}
状态栏是应⽤程序中输出简要信息的区域。⼀般位于主窗⼝的最底部,⼀个窗⼝中最多只能有⼀个状态栏。在 Qt 中,状态栏是通过 QStatusBar类 来实现的。 在状态栏中可以显⽰的消息类型有:
状态栏的创建是通过 QMainWindow 类 提供的 statusBar() 函数来创建;⽰例如下:
// 创建状态栏
QStatusBar* status = statusBar();
// 将状态栏置于窗口中
setStatusBar(status);
在状态栏中显⽰实时消息是通过 showMessage() 函数来实现,⽰例如下:
status->showMessage("Hello, world", 2000);
在状态栏中可以显⽰永久消息,此处的永久消息是通过 标签 来显示的;⽰例如下:
// 创建状态栏
QStatusBar* status = statusBar();
// 将状态栏置于窗口中
setStatusBar(status);
// 创建标签
QLabel* label = new QLabel("提示消息", this);
// 将标签放入状态栏中
status->addWidget(label);
调整显⽰消息的位置,将创建的标签放入到状态栏的右侧
// 将创建的标签放入到状态栏的右侧
QLabel* label2 = new QLabel("右侧提示消息", this);
status->addPermanentWidget(label2);
在 Qt 中,浮动窗⼝也称之为铆接部件。浮动窗⼝是通过 QDockWidget类 来实现浮动的功能。浮动窗口⼀般是位于核心部件的周围,可以有多个。
浮动窗⼝的创建是通过 QDockWidget类 提供的构造⽅法 QDockWidget()函数 动态创建的;示例如下:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 浮动窗口
QDockWidget* dockWidget = new QDockWidget("浮动窗口", this);
// 将浮动窗口置于当前窗口中
addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
}
浮动窗⼝是位于中⼼部件的周围。可以通过 QDockWidget类 中提供 setAllowedAreas() 函数设置其允许停靠的位置。其中可以设置允许停靠的位置有:
示例如下:设置浮动窗口只允许上下停靠
对话框是 GUI 程序中不可或缺的组成部分。⼀些不适合在主窗⼝实现的功能组件可以设置在对话框中。对话框通常是⼀个顶层窗⼝,出现在程序最上层,⽤于实现短期任务或者简洁的⽤⼾交互。Qt常用的内置对话框有:QFiledialog(⽂件对话框)、QColorDialog(颜⾊对话框)、QFontDialog(字体对话框)、QInputDialog (输⼊对话框)和 QMessageBox(消息框) 。
对话框分为 模态对话框 和 ⾮模态对话框。
模态对话框指的是:显⽰后⽆法与⽗窗⼝进⾏交互,是⼀种阻塞式的对话框。使⽤ QDialog::exec() 函数调⽤。
模态对话框适⽤于必须依赖用户选择的场合,⽐如消息显⽰,⽂件选择,打印设置等。
示例:
(1)新建 Qt 项⽬,在 ui ⽂件中的菜单栏中设置两个菜单:“⽂件” 和 “编辑”,在 菜单 “⽂件” 下新建菜单项:“创建” 并将菜单项 “新建” 置于⼯具栏中 ; 如下图⽰:
(2)在 mainwindow.cpp ⽂件中实现:当点击 “新建” 时,弹出⼀个模态对话框;
说明:在菜单项中,点击菜单项时就会触发 triggered() 信号。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 当点击新建时,弹出一个模态对话框,在菜单项中,当点击之后就会触发 triggered 信号
connect(ui->action, &QAction::triggered, [=](){
QDialog dlg(this);
dlg.resize(200, 100);
dlg.exec();
});
}
⾮模态对话框显⽰后独⽴存在,可以同时与⽗窗⼝进⾏交互,是⼀种⾮阻塞式对话框,使用 QDialog::show()函数调用。
⾮模态对话框⼀般在堆上创建,这是因为如果创建在栈上时,弹出的⾮模态对话框就会⼀闪⽽过。同时还需要设置 Qt:WA_DeleteOnClose 属性,⽬的是:当创建多个⾮模态对话框时(如打开了多个非模态窗⼝),为了避免内存泄漏要设置此属性。
⾮模态对话框适⽤于特殊功能设置的场合,⽐如查找操作,属性设置等。
示例:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 非模态对话框
connect(ui->action, &QAction::triggered, [=](){
// 为了防止一闪而过,创建在堆区
QDialog* dlg = new QDialog(this);
dlg->resize(200, 100);
// 当 dlg 无限创建时(即一直不断地打开关闭窗口),设置下面这个属性就可以在关闭非模态对话框时释放这个对象
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
});
}
混合属性对话框同时具有模态对话框和⾮模态对话框的属性,对话框的⽣成和销毁具有⾮模态对话框属性,功能上具有模态对话框的属性。
使⽤ QDialog::setModal() 函数 可以创建混合特性的对话框。通常,创建对话框时需要指定对话框的⽗组件。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 混合属性对话框
connect(ui->action, &QAction::triggered, [=](){
QDialog* dialog = new QDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModal(true);
dialog->resize(200, 100);
dialog->show();
});
}
Qt 提供了多种可复⽤的对话框类型,即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog类。常用标准对话框如下:
消息对话框是应⽤程序中最常⽤的界⾯元素。消息对话框主要⽤于为⽤⼾提⽰重要信息,强制用户进行选择操作。
QMessageBox类中定义了静态成员函数,可以直接调⽤创建不同⻛格的消息对话框,其中包括:
其对应的函数原型如下:
代码示例1:问题提⽰消息对话框
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
resize(800, 600);
QPushButton* btn = new QPushButton("消息对话框", this);
QMessageBox* msg = new QMessageBox(this);
msg->setWindowTitle("Warning Message"); // 设置消息对话框标题
msg->setText("Error Message!"); // 设置消息对话框内容
msg->setIcon(QMessageBox::Question); // 设置消息对话框类型
msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); // 在消息对话框上设置按钮
connect(btn, &QPushButton::clicked, [=](){
msg->show();
});
}
其中可以设置的按钮的类型如下:
颜⾊对话框的功能是允许⽤⼾选择颜⾊。继承⾃ QDialog 类。
常⽤⽅法介绍:
QColorDialog (QWidget *parent = nullptr) //创建对象的同时设置⽗对象
QColorDialog(const QColor &initial, QWidget *parent = nullptr) //创建对象的同时通过 QColor 对象设置默认颜⾊和⽗对象
void setCurrentColor(const QColor &color) //设置当前颜⾊对话框
QColor currentColor() const //获取当前颜⾊对话框
QColor getColor(const QColor &initial = Qt::white \
QWidget *parent = nullptr \
const QString& title = QString() \
QColorDialog::ColorDialogOptions options = ColorDialogOptions()) //打开颜色选择对话框,并返回⼀个QColor对象
// initial:设置默认颜⾊
// parent:设置⽗对象
// title:设置对话框标题
// options:设置选项
void open(QObject *receiver, const char *member) //打开颜⾊对话框
示例代码1:
#include "mainwindow.h"
#include <QPushButton>
#include <QColorDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(800, 600);
QPushButton* btn = new QPushButton("颜色对话框", this);
// 创建颜色对话框
QColorDialog* cdlg = new QColorDialog(this);
connect(btn, &QPushButton::clicked, [=](){
// 打开颜色对话框, 并设置默认颜色为红色
QColor color = cdlg->getColor(QColor(255, 0, 0));
qDebug() << "r = " << color.red();
qDebug() << "g = " << color.green();
qDebug() << "b = " << color.blue();
});
}
效果如下:
代码示例2:
将上面代码的 connect 函数改一下即可:
connect(btn, &QPushButton::clicked, [=](){
// 设置颜色对话框中的颜色
cdlg->setCurrentColor(QColor(200, 100, 190));
cdlg->open();
});
效果如下:
⽂件对话框⽤于应⽤程序中需要打开⼀个外部⽂件或需要将当前内容存储到指定的外部⽂件。常用方法介绍:
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())
2、打开多个⽂件(⼀次可以打开多个⽂件)
QStringList getOpenFileNames(QWidget *parent = nullptr, \
const QString &caption = QString(),\
const QString &dir = QString(), \
const QString &filter = QString(), \
QString *selectedFilter = nullptr,\
QFileDialog::Options options = Options())
3、 保存文件
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 ⽂件过滤器
示例代码1:
#include "mainwindow.h"
#include <QPushButton>
#include <QFileDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(800, 600);
QPushButton* btn = new QPushButton("文件", this);
QFileDialog* fdlg = new QFileDialog(this);
connect(btn, &QPushButton::clicked, [=](){
QString str = fdlg->getOpenFileName(this, // 父对象
"文件", // 文件对话框标题
"D:\\桌面\\jpg", // 打开的路径
"*.jpg"); // 只保留 .jpg 格式文件
qDebug() << str;
});
}
示例代码2,保存文件:
只需要改 connect 中的内容:
QString str = fdlg->getSaveFileName(this, "文件", "D:\\桌面\\jpg", "*.jpg");
Qt 中提供了预定义的字体对话框类 QFontDialog,⽤于提供选择字体的对话框部件。
示例代码:
#include "mainwindow.h"
#include <QPushButton>
#include <QFontDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(800, 600);
QPushButton* btn = new QPushButton("字体", this);
connect(btn, &QPushButton::clicked, [=](){
// 使用 QFontDialog 类的静态方法 getFont 打开字体对话框并设置默认格式
bool flag;
QFont font = QFontDialog::getFont(&flag, QFont("黑体", 36));
// 将 char* 转换为 QString 的方法:.toUtf8().data()
qDebug() << "字体: " << font.family().toUtf8().data();
// 获取字号
qDebug() << "字号: " << font.pointSize();
// 判断字体是否加粗
qDebug() << "是否加粗: " << font.bold();
// 判断字体是否倾斜
qDebug() << "是否倾斜: " << font.italic();
});
}
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());
2、整型输⼊数据对话框
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());
3、选择条目型输⼊数据框
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:可供选择的条目
代码示例1: 浮点型数据输⼊对话框
#include "mainwindow.h"
#include <QPushButton>
#include <QInputDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(800, 600);
QPushButton* btn = new QPushButton("输入框", this);
QInputDialog* idlg = new QInputDialog(this);
connect(btn, &QPushButton::clicked, [=](){
double d = idlg->getDouble(this, "输入框", "浮点型");
qDebug() << "d = " << d;
});
}
代码示例2: 整型数据输⼊对话框
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(800, 600);
QPushButton* btn = new QPushButton("输入框", this);
QInputDialog* idlg = new QInputDialog(this);
connect(btn, &QPushButton::clicked, [=](){
int i = idlg->getInt(this, "输入框", "浮点型");
qDebug() << "i = " << i;
});
}
代码示例3:打开选择条⽬对话框
#include "mainwindow.h"
#include <QPushButton>
#include <QInputDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(800, 600);
QPushButton* btn = new QPushButton("输入框", this);
QInputDialog* idlg = new QInputDialog(this);
connect(btn, &QPushButton::clicked, [=](){
QStringList items;
items << tr("Spring") << tr("Summer") << tr("Fall") << tr("Winter");
QString item = idlg->getItem(this, "输入框", "Item", items);
qDebug() << "item: " << item.toUtf8().data();
});
}
效果如下: