Create Project > Application(Qt) > Qt Widgets Application
generate form
:创建界面,暂不选
Base class
这里选择个
QWidget
(非窗口的普通类可以选顶级类QObject
,以便加入对象树)
QWidget
QDialog
和QMainClass
的父类,是个空窗口QDialog
QMainClass
main.cpp
#include "widget.h"
//应用程序类头文件
#include
/**
* 程序入口
* @brief qMain
* @param argc 命令行参数个数
* @param argv 命令行参数数组
* @return
*/
int main(int argc, char *argv[])
{
//实例化出一个应用程序对象a,该对象有且只有一个
QApplication a(argc, argv);
//窗口类(QWidget的子类)
Widget w;
//显示窗口
w.show();
/*
* 进入消息循环机制(阻塞),关闭窗口时退出
*/
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
class Widget : public QWidget
{
Q_OBJECT //用于支持信号和槽的宏
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_H
同
java
ctrl + f
ctrl + /
选中 + F1
ctrl + 滚轮
ctrl + shift + 上|下
ctrl + i
f4
QPushButton
widget.cpp
,须引入头文件#include
// widget.cpp
#include "widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//设置窗口名称
setWindowTitle("测试QPushButton");
//设置当前窗口大小:用户可缩放
//resize(600, 400);
//设置当前窗口大小:用户不可缩放
setFixedSize(600, 400);
/**
* 创建一个按钮(对象)
*/
/*方式一*/
QPushButton* btn1 = new QPushButton;
//设置父窗口
btn1->setParent(this);
//设置内容
btn1->setText("按钮1");
/*方式二*/
QPushButton* btn2 = new QPushButton("btn2", this);
//移动按钮
btn2->move(100, 0);
}
Widget::~Widget()
{
}
在
Qt
中对于new
出来的对象,如果是QObject
及其衍生类,都无需关心其内存的释放
QObject
是以对象树的形式组织起来的当创建一个
QObject
对象时,QObject
的构造函数会接收一个QObject
指针作为参数,名为parent
,也就是对象指针
所以,在创建QObject
对象时,可以提供一个它的父对象,而我们即将创建的这个QObject
,就会被加入到父对象的children()
列表中
当父对象析构的时候,这个列表中的所有对象也都会被调用析构
这里的父子对象指的是父子窗口的含义
当一个
QObject
对象在堆上创建时,Qt
会同时为其创建一个对象树,要注意的是,对象树中的对象的顺序时没有定义的,所以,销毁这些对象的顺序也是未定义的
任何对象树种的
QObject
对象delete
的时候,如果这个对象有parent
,那么会同时将这个对象从它的parent
的children
中移除;
同时,如果它自身的children()
中的对象也会被delete
如果
QObject
在栈上被创建,Qt
也一样会这样操作
注意:对于打印的顺序,会先打印父对象中的析构函数中,因为这时候并没有进行释放操作,而只是追踪操作,即判断是否还有下级子对象,只有在确定没有子对象时才开始由子到父的顺序进行对象的释放
connect
connect(信号发送者, 发送的信号, 信号接收者, 处理的槽函数)
#include "widget.h"
#include
#include "mypushbutton.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
MyPushButton* btn = new MyPushButton;
btn->setText("点我关闭");
btn->setParent(this);
connect(btn, &QPushButton::clicked, this, &QWidget::close);
}
Widget::~Widget()
{
qDebug() << "Widget 析构函数调用";
}
signals
下,只需要声明,不需要实现void
,可以有参数,且可以重载public slots
下public
下成员函数 或直接用lambda
表达式void
,可以有参数,也可以重载
connect(班长, 起立, 学生, 老师好)
classmonitor.h
#ifndef CLASSMONITOR_H
#define CLASSMONITOR_H
#include
class ClassMonitor : public QObject
{
Q_OBJECT
public:
explicit ClassMonitor(QObject *parent = nullptr);
signals:
void standUp();
};
#endif // CLASSMONITOR_H
classmonitor.cpp
#include "classmonitor.h"
ClassMonitor::ClassMonitor(QObject *parent)
: QObject{parent}
{
}
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
//槽函数除了写在这的public slots中,也可以写在全局函数或者public下
public slots:
void greeting();//需要在源文件中实现
};
#endif // STUDENT_H
student.cpp
#include "student.h"
#include
Student::Student(QObject *parent)
: QObject{parent}
{
}
void Student::greeting() {
qDebug() << "老师好 ~~ ";
}
Widget
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include "classmonitor.h"
#include "student.h"
#include
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
ClassMonitor * monitor;
Student * student;
void classBegin();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//传入this,将其放入对象树中
this->monitor = new ClassMonitor(this);
this->student = new Student(this);
//创建信号槽:班长喊起立,学生喊老师好
connect(monitor, &ClassMonitor::standUp, student, &Student::greeting);
//上课:触发信号槽
classBegin();
}
Widget::~Widget()
{
}
/**
* 上课:触发班长的《起立》信号
* 班长:实例对象要和connect的一致
* @brief Widget::classBegin
*/
void Widget::classBegin() {
emit this->monitor->standUp();
}
classmonitor.h
//...
signals:
void standUp();
void standUp(QString surname);
};
//...
student.h
//...
public slots:
void greeting();//需要在源文件中实现
void greeting(QString surname);
};
//...
student.cpp
//...
void Student::greeting(QString surname) {
/*
* QString是带引号的,如果要去除,需要将其转为char *
* 1、surname.toUtf8() 将QString转为QByteArray
* 2、.data() 将QByteArray转为char *
*/
qDebug() << surname.toUtf8().data() << "老师好 ~~ ";
}
//...
Widget
widget.h
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//传入this,将其放入对象树中
this->monitor = new ClassMonitor(this);
this->student = new Student(this);
/*
* 此时需要通过函数指针来指定函数地址
* 返回值(作用域::*函数指针名)(参数类型列表) = &作用域::函数名
*/
void(ClassMonitor::*monitorSignal)(QString) = &ClassMonitor::standUp;
void(Student::*studentSignal)(QString) = &Student::greeting;
connect(monitor, monitorSignal, student, studentSignal);
classBegin();
}
void Widget::classBegin() {
emit this->monitor->standUp("黄");
}
connect(btn, &QPushButton::clicked, monitor, monitorSingal) //此时无需再调用emit去触发信号
#include "widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->monitor = new ClassMonitor(this);
this->student = new Student(this);
//构建无参信号和槽
void(ClassMonitor::*monitorSignal)() = &ClassMonitor::standUp;
void(Student::*studentSignal)() = &Student::greeting;
connect(monitor, monitorSignal, student, studentSignal);
QPushButton* btn = new QPushButton("上课", this);
connect(btn, &QPushButton::clicked, monitor, monitorSignal);
resize(400, 600);
}
Widget::~Widget()
{
}
disconnect(btn, &QPushButton::clicked, monitor, monitorSignal);
//可以
void(ClassMonitor::*monitorSignal)(Qstring) = &ClassMonitor::standUp;
void(Student::*studentSignal)() = &Student::greeting;
connect(monitor, monitorSignal, student, studentSignal);
//不可以
void(ClassMonitor::*monitorSignal)() = &ClassMonitor::standUp;
void(Student::*studentSignal)(Qstring) = &Student::greeting;
connect(monitor, monitorSignal, student, studentSignal);
Qt5
之前版本的写法不推荐使用
优势:参数直观
劣势:不会对参数类型做匹配
connect(monitor, SIGNAL(standUp()), student, SLOT(greeting()));
emit monitor->standUp();
connect(monitor, SIGNAL(standUp(QString)), student, SLOT(greeting(QString)));
emit monitor->standUp("张");
lambda
表达式
c++ 11
加入的匿名函数对象,用于简化编程
[capture](parameters)mutable -> return-type
{
//...
}
[]
标识一个lambda
的开始,capture
表示函数对象参数
函数对象参数时传递给编译器自动生成的函数对象类的构造函数的
函数对象参数只能使用:当前lambda
所在范围内的可见的局部变量(包括lambda
所在类的this
)
空
=
lambda
函数体内可以使用其所在作用域范围内所有可见的局部变量(包括所在类的this
),并且是值传递(相当于编译器自动按值传递的方式传递了所有局部变量)QPushButton* btn = new QPushButton("上课", this);
[=]() {
btn->setText("上课了"); //如果为空,这里是无法用到btn变量的
}(); //用()来进行调用
&
=
,只不过是用的引用传递的方式(相当于编译器自动按引用传递的方式传递了所有局部变量)this
lambda
所在类中的成员变量a
a
(其他变量将无法使用)按值传递的方式进行传递,这种方式函数体内不能直接去修改a
的拷贝,因为默认时const
的,需要先改造a
的拷贝构造&a
a
以引用的方式进行传递=, &a, &b
a
和b
用引用传递,其余用值传递&, a, b
a
和b
用值传递,其余用引用传递&
可能引起的问题//点击按钮,改变按钮的文本值
QPushButton *btn = new QPushButton("aaa", this);
/*
* 当使用信号和槽的使用,其内部会会进入锁状态,即只读,
* 所以如果使用&引用传递的方式的话可能会出问题
* 所以一般使用=值传递的方式即可
*/
connect(btn, &QPushButton, this, [&](){
btn->setText("bbb"); //可能会引起报错
})
mutable
该关键字可以省略
按值传递函数对象参数时,加上
mutable
关键字之后,可以修改按值传递进来的拷贝(注意是修改拷贝,而非值本身)
/*
* 操作:先点击a按钮,再点击b按钮
* 输出:
* 10
* btn1: 20 //因为使用了mutable关键字,所以可以对m进行修改
* btn2: 10 //因为是值传递,所以改的其实是拷贝,原值未被修改
*/
QPushButton* btn1 = new QPushButton("a", this);
QPushButton* btn2 = new QPushButton("b", this);
btn2->move(100, 0);
int m = 10;
connect(btn1, &QPushButton::clicked, this, [m]()mutable {
m = 20;
qDebug() << "btn1: " << m;
});
connect(btn2, &QPushButton::clicked, this, [=](){
qDebug() << "btn2: " << m;
});
qDebug() << m;
-> 返回值类型
,如果返回值为void
则可以省略
this
的省略对于信号和槽,如果槽函数使用的是
lambda
的形式,那么如果信号接收者是this
的话,可以省略
QPushButton* btn = new QPushButton("点击关闭窗口", this);
connect(btn, &QPushButton::clicked, [=](){
this->close();
});
QMainWindow
提供主窗口程序的类,包含一个菜单栏(
menu bar
)、多个工具栏(tool bars
)、多个锚接部件(dock widgets
)、一个状态栏(status bar
)以及一个中心部件(center widget
),是许多应用程序的基础(如文本编辑器、图片编辑器等)
一个窗口中最多只能有一个
#include "mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(600, 400);
//创建一个菜单栏对象
QMenuBar *bar = menuBar();
//往菜单栏上添加菜单
QMenu *fileMenu = bar->addMenu("文件");
QMenu *editMenu = bar->addMenu("编辑");
QMenu *viewMenu = bar->addMenu("View");
//往菜单上添加菜单项
QAction * newProject = fileMenu->addAction("新建项目");
//添加一个分割线
fileMenu->addSeparator();
QAction * newFile = fileMenu->addAction("新建文件");
//将菜单栏放入窗口中
setMenuBar(bar);
}
MainWindow::~MainWindow()
{
}
一个窗口中允许有多个
#include "mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(600, 400);
//创建一个菜单栏对象
QMenuBar *bar = menuBar();
//往菜单栏上添加菜单
QMenu *fileMenu = bar->addMenu("文件");
QMenu *editMenu = bar->addMenu("编辑");
QMenu *viewMenu = bar->addMenu("View");
//往菜单上添加菜单项
QAction * newProject = fileMenu->addAction("新建项目");
//添加一个分割线
fileMenu->addSeparator();
QAction * newFile = fileMenu->addAction("新建文件");
//将菜单栏放入窗口中
setMenuBar(bar);
//创建一个工具栏对象
QToolBar *toolBar = new QToolBar(this);
//设置可停靠的区域(默认上下左右都可以)
toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
//设置浮动性(默认可浮动)
toolBar->setFloatable(false);
//往工具栏中放置部件
toolBar->addAction(newProject);
//添加分割线
toolBar->addSeparator();
toolBar->addAction(newFile);
//将工具栏放入窗口中(默认放窗口上方)
addToolBar(Qt::LeftToolBarArea, toolBar); //放到窗口的左侧
}
一个窗口最多有一个
#include
#include
//...................................
//创建一个状态栏对象
QStatusBar *staBar = statusBar();
//往状态栏中添加部件
QLabel *label1 = new QLabel("label1", this); //存文本标签部件
QLabel *label2 = new QLabel("label2", this);
staBar->addWidget(label1); //从左侧开始添加
staBar->addPermanentWidget(label2); //从右侧开始添加
//将菜单栏放入窗口中
setStatusBar(staBar);
锚接部件也叫浮动窗口,可以有多个
中心部件可以是各种形式的部件,如文本编辑部件,最多只能有一个
#include
#include
//........................................
//创建一个锚接部件对象
QDockWidget *dock = new QDockWidget("dock1", this);
//设置停靠位置
dock->setAllowedAreas(Qt::TopDockWidgetArea|Qt::RightDockWidgetArea);
//创建和一个文本编辑类的中心部件(中心部件只能有一个)
QTextEdit *edit = new QTextEdit(this);
//将中心部件放入窗口中
setCentralWidget(edit);
//将锚接部件放入窗口中(停靠位置依赖于中心部件)
addDockWidget(Qt::RightDockWidgetArea, dock);
自定义对话框可以分为模态对话框和非模态对话框,区别在于对话框期间是否允许对其他的窗口进行操作,其中模态对话框禁止操作
点击新建文件弹出对话框
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->actionfile->setIcon(QIcon(":/image/aaa.png"));
connect(ui->actionfile, &QAction::triggered, this, [=](){
QDialog dialog(this); //创建模态对话框对象
dialog.resize(200, 300); //设置对话框窗口大小
dialog.exec(); //弹出对话框(该方法会阻塞,所以虽然是栈上创建的对话框对象,创建出来的对话框也不会立马消失)
});
}
MainWindow::~MainWindow()
{
delete ui;
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->actionfile->setIcon(QIcon(":/image/aaa.png"));
connect(ui->actionfile, &QAction::triggered, this, [=](){
//创建非模态对话框对象,不能再创建在栈上,因为lambda直接结束对象消失,会导致对话框窗口一闪而逝
QDialog* dialog = new QDialog(this);
//设置对话框窗口大小
dialog->resize(200, 300);
/*
* 由于是创建在堆上,所以对象只有大窗口关闭才会删除,只是关闭对话框不会被删除
* 所以每次点击都会创建一个对象
* 通过设置Qt::WA_DeleteOnClose属性,可以使得每次关闭对话框时删除其中的对象
*/
dialog->setAttribute(Qt::WA_DeleteOnClose);
//通过show方法弹出的对话框为非模态对话框
dialog->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
QColorDialog
选择颜色
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//弹出拾色器并自定义默认选中的颜色
QColor color = QColorDialog().getColor(Qt::red);
qDebug() << color.rgb();
qDebug() << color.red() << color.green() << color.blue();
}
MainWindow::~MainWindow()
{
delete ui;
}
QFileDialog
选择文件或目录
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//弹出打开文件窗口并设置默认路径、以及指定文件格式
//返回:文件全路径
QString fileName = QFileDialog::getOpenFileName(this, "打开文件", ".", "(*.cpp)");
qDebug() << fileName;
}
MainWindow::~MainWindow()
{
delete ui;
}
QFontDialog
选择字体
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
bool flag;
//弹出字体选择框并指定默认字体和字号大小等
QFont font = QFontDialog::getFont(&flag, QFont("仿宋", 16));
qDebug() << font.family().toUtf8().data(); //字体
qDebug() << font.pointSize(); //字号
qDebug() << font.bold(); //是否有加粗
}
MainWindow::~MainWindow()
{
delete ui;
}
QInputDialog
允许用户输入一个值,并将其值返回
QMessageBox
模态对话框,常用语显示信息、询问问题等
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMessageBox::critical(this, "错误", "错误对话框");
QMessageBox::warning(this, "警告", "警告对话框");
QMessageBox::information(this, "信息", "信息对话框");
/*
* 参数4:关联的按钮,默认YES和NO,可自定义
* 参数5:默认选中的按钮
* 返回值:选中的按钮放
*/
QMessageBox::StandardButton res = QMessageBox::question(this, "询问", "询问对话框", QMessageBox::Save|QMessageBox::Cancel, QMessageBox::Save);
if(res == QMessageBox::Save) {
qDebug("save");
} else {
qDebug("Cancel");
}
}
MainWindow::~MainWindow()
{
delete ui;
}
QPageSetupDialog
为打印机提供纸张相关的选项
QPrintDialog
打印机配置
QPrintPreviewDialog
打印预览
QProgressDialog
显示操作过程
垂直布局
水平布局
网格布局,即自动几行几列的排好
普通按钮,可以通过
icon
属性设置图标
工具按钮,一般用来用作图标按钮
QToolButton/toolButtonStyle
QToolButton/autoRaise
单选按钮
Group Box
进行分组//先设置好单选项的objectname
ui->btn_man->setChecked(true);
connect(ui->btn_woman, &QRasioButton::clicked, [=](){
qDebut() << "选中了woman";
});
多选按钮
Group Box
进行分组QCheckBox/tristate
属性来开启connect(ui->check_item1, &QCheckBox::stateChanged, [=](int state){
if (state == 0) qDebug() << "未选中";
else if(state == 1) qDebug() << "半选中";
else if(state == 2) qDebug() << "选中";
})
以列表的形式来展示内容
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
/*
* 一次添加一个列表项:这种方式可以设置对齐方式(默认左对齐)
*/
QListWidgetItem *item1 = new QListWidgetItem("床前明月光");
//居中对齐
item1->setTextAlignment(Qt::AlignCenter);
QListWidgetItem *item2 = new QListWidgetItem("疑是地上霜");
//放入ListWidget中
ui->listWidget->addItem(item1);
ui->listWidget->addItem(item2);
/*
* 一次添加多个列表项:这种方式不能设置对齐方式
*/
//可以看做是List
QStringList list;
list << "举头望明月" << "低头思故乡";
ui->listWidget->addItems(list);
}
Widget::~Widget()
{
delete ui;
}
用树的形式来展示内
#include "widget.h"
#include "ui_widget.h"
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置头部
ui->treeWidget->setHeaderLabels(QStringList() << "Hero" << "Hero briefing");
//设置根结点
QTreeWidgetItem *powerHeros = new QTreeWidgetItem(QStringList() << "武力" << "法力");
QTreeWidgetItem *iqHeros = new QTreeWidgetItem(QStringList() << "智力");
QTreeWidgetItem *speedHeros = new QTreeWidgetItem(QStringList() << "速度");
//设置二级结点
QTreeWidgetItem *p1 = new QTreeWidgetItem(QStringList() << "张三丰" << "武力100;法力0");
QTreeWidgetItem *p2 = new QTreeWidgetItem(QStringList() << "法海" << "武力20;法力90");
QTreeWidgetItem *i1 = new QTreeWidgetItem(QStringList() << "诸葛亮" << "智力100");
QTreeWidgetItem *i2 = new QTreeWidgetItem(QStringList() << "孙膑" << "智力95");
QTreeWidgetItem *s1 = new QTreeWidgetItem(QStringList() << "盗跖" << "速度90");
QTreeWidgetItem *s2 = new QTreeWidgetItem(QStringList() << "金鹏鸟" << "速度100");
//将二级结点放入根结点
powerHeros->addChild(p1);
powerHeros->addChild(p2);
iqHeros->addChild(i1);
iqHeros->addChild(i2);
speedHeros->addChild(s1);
speedHeros->addChild(s2);
//将结点放入树中
ui->treeWidget->addTopLevelItem(powerHeros);
ui->treeWidget->addTopLevelItem(iqHeros);
ui->treeWidget->addTopLevelItem(speedHeros);
}
Widget::~Widget()
{
delete ui;
}
用表格的形式来展示内
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置列数
ui->tableWidget->setColumnCount(3);
//设置头
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "性别" << "年龄");
//设置行数
ui->tableWidget->setRowCount(5);
//设置内容
QList<QString> names;
names << "张三" << "李四" << "王五" << "赵六" << "周七";
QStringList genders;
genders << "男" << "女" << "男" << "男" << "女";
for(int i = 0; i < 5; ++i) {
int col = 0;
ui->tableWidget->setItem(i, col++, new QTableWidgetItem(names[i]));
ui->tableWidget->setItem(i, col++, new QTableWidgetItem(genders.at(i)));
ui->tableWidget->setItem(i, col, new QTableWidgetItem(QString::number(QRandomGenerator::global()->bounded(20, 25))));
}
}
Widget::~Widget()
{
delete ui;
}
可以给单选按钮、多选按钮进行分组
滚动条
类似
标签页
ui
设计界面类似轮播图,内容可以是任意的组件,不过实际使用界面没有轮播按钮,所以一般要配合按钮使用,即点击按钮进入对应的内容页,所以可以理解为是个可纵可横的标签页
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置默认选项
ui->stackedWidget->setCurrentIndex(0);
//绑定点击事件
connect(ui->btn_tree, &QPushButton::clicked, [=](){
ui->stackedWidget->setCurrentIndex(0);
});
connect(ui->btn_table, &QPushButton::clicked, [=](){
ui->stackedWidget->setCurrentIndex(1);
});
connect(ui->btn_list, &QPushButton::clicked, [=](){
ui->stackedWidget->setCurrentIndex(2);
});
}
Widget::~Widget()
{
delete ui;
}
可以对放置在里面的部件进行布局
锚接部件
下拉框
ui->comboBox->addItem("选项1");
ui->comboBox->addItem("选项2");
ui->comboBox->addItem("选项3");
//默认选中项
ui->comboBox->setCurrentIndex(0); //或setCurrentText("选项1")
字体下拉框
类似标签
类似
同上,只不过没有样式
类似购物车商品数的加减
和上面的相比,数值为
Double
类型
时间选择器
日期选择器
时间日期选择器
横向滚动条
纵向滚动条
标签,可以显示文本或图片(包括
gif
动图)
//放图片
ui->label_img->setPixmap(QPixmap(":/image/butterfly.png"));
//放动图
QMovie *movie = new QMovie(":/image/demo.gif");
ui->label_movie->setMovie(movie);
movie->start();
项目基类选择空部件的
QWidget
即可
Qt
文件Qt
).h
和.cpp
还包括了ui
文件)Widget
)smallwidget.h
#ifndef SMALLWIDGET_H
#define SMALLWIDGET_H
#include
namespace Ui {
class SmallWidget;
}
class SmallWidget : public QWidget
{
Q_OBJECT
public:
explicit SmallWidget(QWidget *parent = nullptr);
~SmallWidget();
private:
Ui::SmallWidget *ui;
};
#endif // SMALLWIDGET_H
smallwidget.cpp
#include "smallwidget.h"
#include "ui_smallwidget.h"
#include
#include
SmallWidget::SmallWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::SmallWidget)
{
ui->setupUi(this);
//数值改变,进度条随之改变
void(QSpinBox::*spinBoxP)(int) = &QSpinBox::valueChanged;
connect(ui->spinBox, spinBoxP, [=](int spinBoxVal) {
ui->horizontalSlider->setValue(spinBoxVal);
});
//进度条改变,数值随之改变
connect(ui->horizontalSlider, &QSlider::valueChanged, [=](int sliderVal) {
ui->spinBox->setValue(sliderVal);
});
}
SmallWidget::~SmallWidget()
{
delete ui;
}
smallwidget.ui
Widget
容器QWidget
mylabel.h
#ifndef MYLABEL_H
#define MYLABEL_H
#include
class MyLabel : public QLabel
{
Q_OBJECT
public:
explicit MyLabel(QWidget *parent = nullptr);
//鼠标进入MyLabel
void enterEvent(QEnterEvent *event);
//鼠标离开MyLabel
void leaveEvent(QEvent *event);
//鼠标在MyLabel中(按下后)移动
void mouseMoveEvent(QMouseEvent *event);
//鼠标在MyLabel中压下
void mousePressEvent(QMouseEvent *event);
//鼠标在MyLable中放开
void mouseReleaseEvent(QMouseEvent *event);
//鼠标在MyLabel中双击
void mouseDoubleClickEvent(QMouseEvent *event);
signals:
};
#endif // MYLABEL_H
mylabel.cpp
#include "mylabel.h"
#include
#include
MyLabel::MyLabel(QWidget *parent)
: QLabel{parent}
{
}
void MyLabel::enterEvent(QEnterEvent *event){
qDebug() << "鼠标进入MyLabel";
}
void MyLabel::leaveEvent(QEvent *event){
qDebug() << "鼠标离开MyLabel";
}
void MyLabel::mouseMoveEvent(QMouseEvent *event){
//鼠标移动中获取按下的键需要用buttons(),因为移动过程中可能同时按下了多个键
if (event->buttons() & Qt::LeftButton) {
qDebug() << "移动过程中按下了鼠标左键";
}
qDebug() << "鼠标在MyLabel中(按下后)移动";
}
void MyLabel::mousePressEvent(QMouseEvent *event){
Qt::MouseButton btn = event->button();
if (btn == Qt::LeftButton) {
qDebug() << "按下了鼠标左键";
}
//x, y:在控件MyLabel的位置
qDebug() << QString("鼠标在MyLabel中压下:x=%1, y=%2").arg(event->x()).arg(event->y());
}
void MyLabel::mouseReleaseEvent(QMouseEvent *event){
qDebug() << "鼠标在MyLable中放开";
}
void MyLabel::mouseDoubleClickEvent(QMouseEvent *event) {
qDebug() << "鼠标在MyLable中双击";
}
ui
中的Label
提升为MyLabel
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//定时器事件
void timerEvent(QTimerEvent *event);
private:
Ui::Widget *ui;
//每1秒定时器标识
int timer1;
//每2秒定时器标识
int timer2;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//开启定时器(单位毫秒)
this->timer1 = startTimer(1000);
this->timer2 = startTimer(2000);
}
Widget::~Widget()
{
//删除定时器
killTimer(this->timer1);
killTimer(this->timer2);
delete ui;
}
void Widget::timerEvent(QTimerEvent *event) {
int timerId = event->timerId();
static int timer1num = 1;
static int timer2num = 1;
if (timerId == this->timer1) {
ui->label_per1->setText(QString::number(timer1num++));
} else if (timerId == this->timer2) {
ui->label_per2->setText(QString::number(timer2num++));
}
}
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建定时器类的对象
QTimer *timer1 = new QTimer(this);
QTimer *timer2 = new QTimer(this);
//启动并设置interval,当达到事件时会抛出timeout信号
timer1->start(1000);
timer2->start(2000);
//绑定timeout信号
connect(timer1, &QTimer::timeout, [=](){
static int num = 1;
ui->label_per1->setText(QString::number(num++));
});
connect(timer2, &QTimer::timeout, [=](){
static int num = 1;
ui->label_per2->setText(QString::number(num++));
});
}
bool eventFilter(Object* obj, QEvent *e);
/*
* 作用:可以对事件进行拦截处理
* 返回值:是否继续往下分发事件,true表示不继续
*/
bool event(QEvent *event);
widget.h
class Widget: ...
public:
bool eventFilter(QObject *, QEvent *);
widget.cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
//给控件安装过滤器
ui->mylabel->installEventFilter(this);
}
/*
* obj: 空间对象,用于区分控件
* e: 事件对象
*/
bool Widget::eventFilter(QObject *obj, QEvent *e) {
//拦截mylabel中的事件
if(obj == ui->mylabel) {
//拦截其中的鼠标按下事件
if(e->type() == QEvent::MouseButtonPress) {
//...
return true;
}
}
//其他对象的时间交给父类处理
return QWidget::eventFilter(obj, e);
}
bool MyLabel::event(QEvent *e) {
//拦截鼠标按下事件
if(e->type() == QEvent::MouseButtonPress) {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
qDebug() << ev->x() << ev->y();
return true; //不在继续往下分发
}
//其他事件交给父类处理
return QLabel::event(e);
}
会自动触发事件
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void paintEvent(QPaintEvent *);
private:
Ui::Widget *ui;
int posX;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->posX = 0;
connect(ui->btn, &QPushButton::clicked, [=](){
posX += 20;
if (posX > this->width()) {
posX = 0; //如果超出窗口宽度,置0
}
//手动调用绘图事件
//repaint(); 效率比update低
update();
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *)
{
/*
* 创建一个绘画者对象
* 构造器参数表示绘画设备,即在哪里画画
* this表示在当前窗口中画
*/
QPainter painter(this);
/*
* 设置画笔
* 用于自定义画笔风格,可以不设置
* 构造器可以指定画笔颜色
*/
QPen pen(QColor("#f99"));
//设置画笔宽度(默认1)
pen.setWidth(2);
//设置画笔风格
pen.setStyle(Qt::DotLine);
//添加画笔
painter.setPen(pen);
/*
* 设置画刷
* 用于填充封闭形状,可不设
* 构造器可以指定画刷颜色
*/
QBrush brush(Qt::cyan);
//设置画刷风格
brush.setStyle(Qt::Dense1Pattern);
//添加画刷
painter.setBrush(brush);
//画线
painter.drawLine(QPoint(0, 0), QPoint(200, 200));
//画(椭)圆(圆心,max x半径,max y半径)
painter.drawEllipse(QPoint(100, 100), 100, 50);
/*
* 画矩形
* QRect(左上角坐标, 宽高)
*/
painter.drawRect(QRect(QPoint(20, 20), QSize(50, 50)));
/*
* 写字(在指定的区域内)
*/
painter.drawText(QRect(100, 10, 150, 20), "hello qt6");
//画资源图片(绘画起点|指定区域,资源图片位置)
painter.drawPixmap(this->posX, 0, QPixmap(":/image/luffy.png"));
}
点击移动按钮,移动图片位置
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPen pen(QColor("#f99"));
painter.setPen(pen);
QBrush brush(Qt::cyan);
painter.setBrush(brush);
painter.drawEllipse(QPoint(100, 100), 50, 50);
//设置抗锯齿能力(会降低成图效率)
painter.setRenderHint(QPainter::Antialiasing);
painter.drawEllipse(QPoint(300, 100), 50, 50);
}
//画一个矩形
painter.drawRect(QRect(20, 20, 50, 50));
//移动画家的绘画起点(默认(0, 0))
painter.translate(100, 0);
//在画一个一样的矩形(由于绘画起点不一样,所以不会被覆盖)
painter.drawRect(QRect(20, 20, 50, 50));
//保存当前的画家状态(绘画起点位置)
painter.save();
//再次移动画家的绘画起点((100, 0) -> (200, 0))
painter.translate(100, 0);
//恢复画家状态((200, 0) -> (100, 0))
painter.restore();
指的是继承
QPainterDevice
的子类,Qt
提供了很多这样的类,如:QPixmap, QBitmap, QImage, QPicture
专门为图像在屏幕上显示做了优化,往窗口绘画示例
//写入文件示例
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
/*用QPixmap做绘图设备*/
//创建设备对象并设置设备大小
QPixmap pix(300, 300);
//设置背景色(默认为黑色)
pix.fill(Qt::white);
QPainter painter(&pix);
painter.setPen(QPen(QColor("#f99")));
painter.drawEllipse(QPoint(150, 150), 100, 100);
//将绘好的图保存
pix.save("D:/data/demo.png");
}
Widget::~Widget()
{
delete ui;
}
是
QPixmap
的一个子类,色深限定为1(即只有黑白色),可以使用QPimap.isQBitmap()
函数来确定一个QPixmap
是不是QBixmap
专门为图像的像素级访问做了优化
//写入文件示例
//创建设备对象并设置设备大小以及色位类型
QImage img(300, 300, QImage::Format_RGB32);
//设置背景色(默认为黑色)
img.fill(Qt::white);
QPainter painter(&img);
painter.setPen(QPen(QColor("#f99")));
painter.drawEllipse(QPoint(150, 150), 100, 100);
//将绘好的图保存
img.save("D:/data/demo.png");
//往窗口绘图 & 修改像素点 示例
void Widget::paintEvent(QPaintEvent *) {
QImage img;
img.load(":/image/demo.png");
QPinter painter(this);
//修改像素点
for(int i = 100; i < 150; ++i) {
for(int j = 100; j < 150; ++j) {
QRgb p = qRgb(255, 0, 0);
img.setPixel(i, j, p); //将坐标为(i, j)的像素改为p
}
}
painter.drawImage(0, 0, img);
}
可以记录和重现
QPainter
的各条命令
//记录命令
#include "widget.h"
#include "ui_widget.h"
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPicture pic;
QPainter painter;
//开始往设备pic上绘图
painter.begin(&pic);
painter.drawEllipse(QPoint(150, 150), 100, 100);
//结束绘图
painter.end();
//保存绘图命令
pic.save("D:/data/pic");
}
Widget::~Widget()
{
delete ui;
}
//重现命令
void Widget::paintEvent(QPaintEvent *) {
QPicture pic;
pic.load("D:/data/pic");
painter.drawPicture(0, 0, pic);
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
//在这行代码之后写自己的代码
ui->setupUi(this);
//使用绝对路径方式:根据ui设计中的变量名进行图标设置
//ui->actionfile->setIcon(QIcon("C:\\Users\\Administrator\\Desktop\\aaa.png"));
/*
* 使用资源路径方式
* 1.可以在项目根路径中添加一个image目录
* 2.创建qrc文件:文件 -> new file -> Qt -> Qt Resource File(一般起名res)
* 3.添加前缀:即资源文件子目录,如/
* 4.添加文件:将image中的图片选中
* 5.build
* 6.可以看到rec.qrc -> / -> image -> aaa.png 这样的目录结构
* 7.冒号 + 前缀名 + 文件名
*/
ui->actionfile->setIcon(QIcon(":/image/aaa.png"));
}
MainWindow::~MainWindow()
{
delete ui;
}
文件读写类
#include "widget.h"
#include "ui_widget.h"
#include
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->check_btn, &QPushButton::clicked, [=](){
QString filePath = QFileDialog::getOpenFileName(this, "打开文件", "A:\\Tools\\WinRAR", "(*.txt)");
if (!filePath.isEmpty()) {
ui->title_line->setText(filePath);
//创建文件对象
QFile file(filePath);
/*读取文件*/
//设置打开方式为只读
file.open(QIODevice::ReadOnly);
//一次全部读取
//QByteArray array = file.readAll();
//一次读取一行
QByteArray array;
while(!file.atEnd()) {
array += file.readLine();
}
//QByteArray到QString存在隐式转换
ui->content_text->setText(array);
//关闭流
file.close();
/*写入文件*/
//WriteOnly为覆盖,Append为追加
file.open(QIODevice::Append);
file.write("abc");
file.close();
} else {
QMessageBox::warning(this, "警告", "未选择文件");
}
});
}
Widget::~Widget()
{
delete ui;
}
文件信息类
QFileInfo info(filePath);
//后缀名
info.suffix(); //txt
//文件大小
info.size();
//文件名
info.fileName();
//文件路径
info.filePath();
//创建时间(birthTime)
info.created().toString("yyyy-MM-dd hh:mm:ss");
//最后修改时间
info.lastModified().toString("yyyy/MM/dd hh:mm:ss");