1.基础理解
1.1初始代码
源文件
cpp#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }QApplication是QT程序中必备的对象,他需要获取main中的命令行参数和命令行参数个数
w是定义好的类的对象,使用show()接口可以让控件显示出来
头文件
cpp#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; }; #endif // WIDGET_H1.QWidget是我们选择的父类,其为QT的sdk中内置的类,使用的时候直接包含和类同名的头文件即可
使用时,先直接使用,如果发现没有包含头文件再包含即可,因为头文件包含是可以间接包含的
2.Q_OBJECT 是一个宏,展开之后会生成一大堆代码,当我们某个类想使用信号和槽的时候就要引入该宏
**3.parent指针:**QT中引入了对象树的概念,创建QT的对象需要把对象挂到对象树上,往树上挂的时候需要指定父节点
ui文件
点开之后会进入图形化设计界面,他的文件内容本质上是一个xml格式的代码
pro文件
qmake和.pro文件的作用和Makefile的作用是类似的
1.2实现简单helloworld窗口
Label标签
ui拖拽实现
先点击.ui文件,进入图形化设计窗口,然后将label拖入窗口,修改label的名字为helloworld
代码实现
如果使用的是QWIDGET类,就写到widget的构造函数中
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //创建基于父对象widget w的子类对象label QLabel* label = new QLabel(this); //设置标签文本 label->setText("hello"); }疑问:如果我们将对象申请在栈上,启动程序会发生什么?
会让窗口无法显示label,因为label对象在构造函数的栈空间释放的时候跟着释放了
所以我们选择使用堆空间给label
疑问:这里动态申请的对象空间为什么不用释放资源?
不是不释放,而是不需要手动释放资源,一般会在窗口消失的时候根据对象树的结构对所有对象资源进行释放
补充:QT中的库
QString,QVector等,他们和c++后来完善的std::string,std::vector类似,不过在QT开发中还是使用QT库中的会更好
Line Edit编辑框与Text Edit编辑框
代码实现:用编码创建编辑框
cpp#include "widget.h" #include "ui_widget.h" #include<QLineEdit> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); QLineEdit* line = new QLineEdit(this); line->setText("hello world"); } Widget::~Widget() { delete ui; }
Button按钮
代码实现:使用ui拖拽创建button
cpp#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick); } Widget::~Widget() { delete ui; } void Widget::handleClick() { if(ui->pushButton->text() == QString("hello")) { ui->pushButton->setText("hi"); } else { ui->pushButton->setText("hello"); } }核心是使用了connect接口,该接口可以让按钮关联信号槽,类似监听
connect格式解释:
参数1:表示谁发送信号
参数2:表示表示如何触发信号
参数3:表示负责处理信号的对象
参数4:表示接受到信号之后的处理函数地址(由负责处理信号的对象提供的成员函数)
注意:
pushButton是objectName的值,如果修改了这里objectName的值,那么使用的时候也要修改名字
疑问:我们应该怎么选择构造界面的形式?使用图形化方式还是纯代码方式?
两者皆要,因为图形化适用于界面固定,纯代码方式适合界面动态变化跳转的情况
疑问:qt中的命名规范是什么?
小驼峰命名:给变量和函数eg:studentCount
大驼峰命名:给类
eg:QApplication
1.3实现自定义的标签对象
我们除了直接使用库的QLabel外,还可以根据实际需求创建自定义的label类
实际上就是通过继承库的QLabel来拓展更多自定义功能
头文件
cpp#ifndef MYLABEL_H #define MYLABEL_H #include<Qlabel> #include<QWidget> class MyLabel : public QLabel { public: MyLabel(QWidget* parent); ~MyLabel(); }; #endif // MYLABEL_H源文件
cpp#include "mylabel.h" MyLabel::MyLabel(QWidget* parent) : QLabel(parent) { } MyLabel::~MyLabel() { }注意:
**1.**构造函数一定要有parent,这是对象树生效的前提
**2.乱码处理:**由于windows默认的字符集不是utf8,所以我们直接使用cout输出中文字符会出现乱码,qt库QDebug可以帮我们自动解决转码问题
使用方式:
cppqDubug() << "中文字符";快捷键:
1.头/源文件切换:F4
2.利用声明生成定义代码:Alt+Enter
1.4QT中的坐标系
qt使用的坐标系是左手坐标系,y轴往下是正方向,x轴往右是正方向
**对于没有父元素的控件:**原点为整个屏幕的左上角
**对于有父元素的控件:**原点为父元素的左上角
我们可以使用两种方式来控制控件的位置
1.图形化界面直接移动:快速定位,但是不精确
2.编码控制:更精细化(使用move(水平移动像素值,垂直移动像素值))
2.信号和槽
信号和槽的三个重要要素
**1.信号源:**信号由谁发出
**2.信号类型:**是那种类型的信号
**3.信号处理(槽):**信号处理的函数,也叫槽,本质上是回调函数
2.1connect函数与disconnect函数
建立信号和槽的连接:connect
connect是QObject提供的静态成员函数,而QObject是qt中所有类的祖宗类,所以所有的控件实例化对象都可以使用connect进行信号处理
结构大致如下:
注意:
1.connect的第一和第二个参数必须是同一个类的,简单来说,我们的信号源是QPushButton,那么信号触发的类型也要是QPushButton的,不能是其他控件的
2.图标中,像梳子的表示槽函数,像wifi信号的表示信号函数
eg:
click表示进行点击操作,clicked表示触发了点击信号(已经被点击)
断开信号和槽的连接:disconnect
使用方法和connect类似
cppdisconnect(this,&Widget::mySignal,this,&Widget::handleMySignal);
2.2自定义信号与槽
使用前提:在对应类中写下Q_OBJECT宏
自定义槽:
方法一:使用connect(代码创建控件)
我们只要在负责处理信号的类中声明一个槽函数,然后再.cpp文件中对槽函数进行实现即可
最后connect就可以使用我们在类中声明的自定义槽函数
方法二:通过槽函数名绑定(图形化创建控件)
我们可以直接在图形化界面绑定槽函数,然后qtcreator就会自动生成自定义槽函数的声明的空定义
cppvoid Widget::on_pushButton_clicked() { }然后底层就调用了根据槽函数名绑定控件的方法,从而不用使用connect
补充:
如果槽函数比较简单且为单次使用,我们可以使用lambda函数来当成槽函数使用
自定义信号:
构建自定义信号,只需要写出声明即可,qt会自动生成信号函数的定义,返回值必须是void
但是和qt内置的信号不同,他需要我们在特定情况下手动发送信号
在widget中直接声明信号函数即可,不用自己写定义
在connect了自定义信号和对应槽函数后,我们还需要在点击按钮触发clicked信号之后进入的槽函数on_pushButton_clicked中发送自定义信号,从而才能进入自定义信号处理槽函数中
2.3信号与槽的参数
信号和槽都可以携带参数,主要目的是为了复用一套信号槽,实现不同的效果(类似多态)
信号的参数个数大于等于槽的参数个数
假设槽的参数个数为n,信号的前n个参数槽的参数必须完全一致,前n个参数会从信号传递给槽,剩下的都被槽直接丢弃










