目录
1、创建第一个Qt程序
Create Project->Qt Widgets Application(创建一个Qt应用,包含一个基于qt设计师的主窗体)
->Location(不能有空格和中文,可以有下划线),路径选择不能有中文(重要!!!)->Build System(选择qmake,ps:一般的Qt工程你就直接使用qmake就可以了,cmake的强大功能一般人是用不到的 //参考的另一篇博客)->Details(QWidget是QDialog和QMainWindow的父类,Qwidget是空窗口,QMainWindow多了工具栏,QDialog是对话框),选择QWidget作为基类,取消Generate form使用代码编写。->Kits(选择套件)->Summary(finish)团队开发时,添加到版本控制系统(svn,vss,git)
main函数代码
#include "mywidget.h"
#include <QApplication>// 包含一个应用程序类的头文件
// main程序入口 argc命令行变量的数量 argv命令行变量的数组
int main(int argc, char *argv[])
{
QApplication a(argc, argv);// a应用程序对象,在qt中,有且仅有一个
MyWidget w;// 创建窗口对象,MyWidget的父类->QWidget
w.show();// 窗口对象 默认不会显示,必须调用show方法显示
return a.exec();//让应用程序对象a进入消息循环机制,等待用户点叉叉,使得窗口不会一闪而过,使代码阻塞到这一行
}
2、命名规范以及快捷键
.pro文件不要添加任何东西,除非你知道写的是什么。.pro文件就是工程文件,它是qmake自动生
成的用于生产makefile的配置文件。
QT += core gui //Qt包含的模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets//大于4版本以上,包含widget模块
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
//源文件
SOURCES += \
main.cpp \
mywidget.cpp
//头文件 自动生成的
HEADERS += \
mywidget.h
Qt基本模块
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>//窗口类头文件 QWidget
class MyWidget : public QWidget
{
Q_OBJECT // Q_OBJECT宏,允许类中使用信号和槽的机制
public:
MyWidget(QWidget *parent = nullptr); // 有参构造函数
~MyWidget();
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
// 命名规范
// 类名 首字母大写,单词和单词之间首字母大写
// 函数名 变量名称 首字母小写,单词和单词之间首字母大写
// 快捷键
// 注释 ctrl + /
// 运行 ctrl + r
// 编译 ctrl + b
// 字体缩放 ctrl + 鼠标滚轮
// 查找 ctrl + f
// 整行移动 ctrl + shift + ⬆或者⬇
// 帮助文档 F1
// 自动对齐 ctrl + i
// 同名之间的.h和.cpp切换 F4
// 帮助文档,左侧的帮助;在Qt5.16\mingw49_32\bin的Qt助手
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)// 初始化列表
{
}
MyWidget::~MyWidget()
{
}
3、QPushBottom的创建
构造函数里创建
#include "mywidget.h"
#include <QPushButton>
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)// 初始化列表
{
// 创建一个按钮
QPushButton * btn = new QPushButton;
// btn->show();// show以顶层方式弹出窗口控件
// 让btn对象 依赖在 MyWdget窗口中
btn->setParent(this);
// 显示文本
btn->setText("first button");
// 创建第二个按钮 按照控件的大小创建窗口
QPushButton * btn2 = new QPushButton("second button",this);
// 重置窗口大小 长x宽
resize(600,400);
// 移动btn2按钮,设置坐标
btn2->move(100,100);
// 设置固定窗口大小,用户不能改变串窗口大小
setFixedSize(600,400);
// 设置窗口标题
setWindowTitle("第一个窗口");
}
MyWidget::~MyWidget()
{
}
4、对象树
父类先构造,子类先析构
在Qt中创建对象的时候会提供一个Parent对象指针。
QObject是以对象树的形式组织起来的。
当你创建一个QObject对象时候,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是Parent,也就是父对象指针。
这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父类对象的children()列表。
当父类对象析构的时候,这个列表中的所有对象也会被析构(注意:这里的父对象并不是继承意义的父类)
QWdget是能够在屏幕上显示的一切组件的父类。
QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时侯,应用程序将共刑除,那么,我们希望属于这个对话框的按钮、图标等应该一起被迸除。事实就是如此,因为这些都是对话框的子组件。
MyPushButton类的创建
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include <QPushButton>//继承QPushButton,没有这个选择就先选择继承它的父亲
class MyPushButton : public QPushButton
{
Q_OBJECT
public:
explicit MyPushButton(QWidget *parent = nullptr);
~MyPushButton();
signals:
};
#endif // MYPUSHBUTTON_H
#include "mypushbutton.h"
#include <QDebug>//打印输出
MyPushButton::MyPushButton(QWidget *parent)
: QPushButton(parent)//换父亲
{
qDebug()<<"我的按钮类构造调用";
}
MyPushButton::~MyPushButton()
{
qDebug()<<"我的按钮类析构调用";
}
打印先打印的是儿子的析构,但是是后面释放。
#include "mywidget.h"
#include <QPushButton>
#include <mypushbutton.h>
#include <QDebug>//打印输出
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)// 初始化列表
{
// 创建一个自己的按钮对象
MyPushButton *mybtn = new MyPushButton;
mybtn->setText("我自己的按钮");
mybtn->move(200,0);
mybtn->setParent(this);
qDebug()<<"MyWidget构造";
}
MyWidget::~MyWidget()
{
qDebug()<<"MyWidget析构";
}
总结:当创建的对象在堆区时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放的操作(就是不用deletex),将对象会放入到对象树中。一定程度上简化了内存回收机制
5、Qt中的坐标系
左上角为(0,0),x向右增大,y向下增大
6、信号和槽
6.1 实现点击按钮关闭窗口
connect( 信号的发送者,发送的具体信号,信号的接受者,信号的处理(槽))
信号槽的优点:松散耦合,信号发送端和接受端本身是没有关联的,通过connect连接将两端耦合在一起。
#include "mywidget.h"
#include <QPushButton>
#include <mypushbutton.h>
#include <QDebug>//打印输出
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)// 初始化列表
{
// 创建一个自己的按钮对象
MyPushButton *mybtn = new MyPushButton;
mybtn->setText("我自己的按钮");
mybtn->move(200,0);
mybtn->setParent(this);
// 点击我的按钮,关掉窗口
// 参数1:信号的发送者,参数2:发送的具体信号(点击)函数的地址;参数3:信号的接受者this窗口,参数4:信号的处理(槽)函数地址
connect(mybtn,&MyPushButton::clicked,this,&MyWidget::close);
//connect(mybtn,&QPushButton::clicked,this,&QWidget::close);// 用父类的也可以
}
MyWidget::~MyWidget()
{
}
6.2 自定义的信号和槽
自定义信号:写到signals下;返回值是void,只需要声明,不需要实现;可以有参数,可以重载。
自定义槽:早期Qt槽函数必须写在public slot下,高级版本可以写道public或者全局下;返回值是void,需要声明,也需要实现;可以有参数,可以重载。
触发自定义信号:emit
#include "widget.h"
// Teacher 类 老师类
// Student 类 学生类
// 下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
// 创建老师和学生对象,并且指定父亲,就不用释放
this->zt = new Teacher(this);
this->st = new Student(this);
connect(zt,&Teacher::Hungry,st,&Student::treat);
// 调用下课,触发老师饿了,随后学生响应
classisover();
}
Widget::~Widget()
{
}
void Widget::classisover()
{
// 下课函数 调用后触发老师饿了信号
emit zt->Hungry();
}
6.3 自定义的信号和槽发生重载的解决
1.需要利用函数指针明确指向函数的地址,成员函数指针需要加上作用域
2.QString->char * 先转成QByteArray(.toUtf8())再转char*(),.data的返回值是char *
Widget代码
#include "widget.h"
// Teacher 类 老师类
// Student 类 学生类
// 下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
// 创建老师和学生对象,并且指定父亲,就不用释放
this->zt = new Teacher(this);
this->st = new Student(this);
//connect(zt,&Teacher::Hungry,st,&Student::treat);
// 调用下课,触发老师饿了,随后学生响应
//classisover();
// 函数指针->函数地址,&+函数名
void(Teacher::*teacherSignal)(QString) = &Teacher::Hungry;// 成员函数的函数指针
void(Student::*studentSlot)(QString) = &Student::treat;
// 当出现重载的时候,需要出现设置信号和槽的函数地址
connect(zt,teacherSignal,st,studentSlot);//重载出现二义性
classisover();
}
Widget::~Widget()
{
}
void Widget::classisover()
{
// 下课函数 调用后触发老师饿了信号,两个信号
emit zt->Hungry();
emit zt->Hungry("宫保鸡丁");
}
槽函数重载
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent)
: QObject{parent}
{
}
void Student::treat()
{
qDebug()<<"请老师吃饭";
}
void Student::treat(QString foodname)// 重载treat
{
//打印QString类型有引号,要转成char*就没有引号
//qDebug()<<"请老师吃饭,老师要吃:"<<foodname;
// QString->char * 先转成QByteArray(.toUtf8())再转char*(),data的返回值是char *
qDebug()<<"请老师吃饭,老师要吃:"<<foodname.toUtf8().data();
}