QT学习笔记(一)

2022年01月13日 阅读数:5
这篇文章主要向大家介绍QT学习笔记(一),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

一、在pro文件里

.pro就是工程文件(project),它是qmake自动生成的用于生产makefile的配置文件。.pro文件的写法以下:
注释
从“#”开始,到这一行结束。
模板变量告诉qmake为这个应用程序生成哪一种makefile。下面是可供使用的选择:TEMPLATE = app; app -创建一个应用程序的makefile。这是默认值,因此若是模板没有被指定,这个将被使用。c++

#指定生成的应用程序名
TARGET = QtDemo
#工程中包含的头文件
HEADERS += include/painter.h
#工程中包含的.ui设计文件
FORMS += forms/painter.ui
#工程中包含的源文件
SOURCES += sources/main.cpp sources
#工程中包含的资源文件
RESOURCES += qrc/painter.qrcweb

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
这条语句的含义是,若是QT_MAJOR_VERSION大于4(也就是当前使用的Qt5及更高版本)须要增长widgets模块。若是项目仅需支持Qt5,也能够直接添加“QT += widgets”一句。不过为了保持代码兼容,最好仍是按照QtCreator生成的语句编写。express

#配置信息
CONFIG用来告诉qmake关于应用程序的配置信息。
CONFIG += c++11 //使用c++11的特性
在这里使用“+=”,是由于咱们添加咱们的配置选项到任何一个已经存在中。这样作比使用“=”那样替换已经指定的全部选项更安全。编程


pro文件里注释是用 #安全

QT       += core gui     #包含的模块
QT       += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets#大于4版本以上的 包含widget模块

TARGET = tcpTestServer #目标 生成的.exe程序的名称

TEMPLATE = app # 模板 应用程序模板 Application


SOURCES += main.cpp\   # 源文件
        mainwindow.cpp

HEADERS  += mainwindow.h  # 头文件

FORMS    += mainwindow.ui


二、 一些命名规范

//命令规范
//类名 首字母大写 单词和单词之间首字母大写
//函数名 变量名称 首字母小写 单词和单词之间首字母大写app

//快捷键
//注释和取消注释都是 ctrl + /
//运行 ctrl + r
//编译 ctrl+b
//ctrl + f 查找
//自动对齐 ctrl +i
//同名之间的**.h和.cpp文件之间的切换** F4
//帮助文档 F1tcp


三、在.cpp文件里进行一些基础的设置

myWidgetcppsvg

#include "mywidget.h"
#include "ui_mywidget.h"
#include<QPushButton> //按钮控制的头文件

myWidget::myWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::myWidget)
{
   
   
    //建立第一个按钮
    QPushButton * btn1=new QPushButton;//建立一个按钮并显示
    btn1->show();//show以顶层的方式弹出控件
    btn1->setParent(this);//让btn对象 依赖在myWidget窗口中 this指针指向当前对象 myWidget

    //让按钮里显示指定的文字
    btn1->setText("Mr.liang 的第一个按钮");

    //建立第二个按钮 按照控件的大小建立窗口
    QPushButton * btn2=new QPushButton("第二个按钮",this);
    btn2->show();

    //移动btn1的位置
    btn1->move(100,100);

    //从新设置按钮的大小
    btn1->resize(200,30);

    //重置窗口的大小 此时用户是能够随意拖拽窗口的大小的
    resize(555,555);

    //设置固定的窗口大小
    setFixedSize(600,400);

    //设置窗口标题
    setWindowTitle("Mrliang");

    //ui->setupUi(this);  //把这行代码注释掉能够自定义窗口title
}

myWidget::~myWidget()
{
   
   
    delete ui;
}


设置好的窗口界面这样的:
在这里插入图片描述
qt中的对象树
在这里插入图片描述函数


四、添加mypushbutton.h 和mypushbutton.cpp文件进行父类调用子类的实现,此时的父类是mywidgetqs


其实主要是经过引入对象树的概念,来说解父类和子类的构造和析构顺序:
构造:先父类再子类
析构:先子类再父类
ui


此时文件包含:
在这里插入图片描述mypushbutton.h

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton : public QPushButton
{
   
   
    Q_OBJECT
public:
    explicit MyPushButton(QWidget *parent = nullptr);

   ~MyPushButton();//析构函数
signals:

};

#endif // MYPUSHBUTTON_H

mypushbutton.cpp

#include "mypushbutton.h"
#include<QDebug> //包含打印信息的头文件

MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)
{
   
   
    qDebug()<<"个人按钮类构造调用";

}

MyPushButton::~MyPushButton()
{
   
   
    qDebug()<<"个人按钮析构";
}

此时的mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include<QPushButton> //按钮控制的头文件
#include"mypushbutton.h"
#include<QDebug> //包含打印信息的头文件


myWidget::myWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::myWidget)
{
   
   
    //建立第一个按钮
    QPushButton * btn1=new QPushButton;//建立一个按钮并显示
    btn1->show();//show以顶层的方式弹出控件
    btn1->setParent(this);//让btn对象 依赖在myWidget窗口中 this指针指向当前对象 myWidget

    //让按钮里显示指定的文字
    btn1->setText("Mr.liang 的第一个按钮");

    //建立第二个按钮 按照控件的大小建立窗口
    QPushButton * btn2=new QPushButton("第二个按钮",this);
    btn2->show();

    //移动btn1的位置
    btn1->move(100,100);

    //从新设置按钮的大小
    btn1->resize(200,30);

    //重置窗口的大小 此时用户是能够随意拖拽窗口的大小的
    resize(555,555);

    //设置固定的窗口大小
    setFixedSize(600,400);

    //设置窗口标题
    setWindowTitle("Mrliang");


    //建立一个我本身的按钮
    MyPushButton * mybtn=new MyPushButton;
    mybtn->setText("Mrliangz本身的按钮");
    mybtn->move(200,200);
    mybtn->setParent(this);//设置到对象树中

//    myWidget::~myWidget()
//    {
   
   
//        qDebug()<<"myWidget的析构调用";
//    };

    //ui->setupUi(this);  //把这行代码注释掉能够自定义窗口title
}


myWidget::~myWidget()
{
   
   
     qDebug()<<"myWidget的析构调用";
     
    delete ui;
}



五、qt里的窗口坐标系

在这里插入图片描述
对于嵌套窗口,其坐标是相对于父窗口而言


六、信号和槽

主要经过槽的技术实现按钮和信号的关联;

伪代码:
connect( 信号的发送者,发送的具体信号,信号的接收者,信号的处理(槽) )

**信号槽的优势:松散耦合,信号发送槽和接收端自己是没有关联的;经过connct链接将两端链接在一块儿 **

实现代码:

#include "mywidget.h"
#include "ui_mywidget.h"
#include<QPushButton> //按钮控制的头文件
#include"mypushbutton.h"
#include<QDebug> //包含打印信息的头文件


myWidget::myWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::myWidget)
{
   
   
    //建立第一个按钮
    QPushButton * btn1=new QPushButton;//建立一个按钮并显示
    btn1->show();//show以顶层的方式弹出控件
    btn1->setParent(this);//让btn对象 依赖在myWidget窗口中 this指针指向当前对象 myWidget

    //让按钮里显示指定的文字
    btn1->setText("Mr.liang 的第一个按钮");

    //建立第二个按钮 按照控件的大小建立窗口
    QPushButton * btn2=new QPushButton("第二个按钮",this);
    btn2->show();

    //移动btn1的位置
    btn1->move(100,100);

    //从新设置按钮的大小
    btn1->resize(200,30);

    //重置窗口的大小 此时用户是能够随意拖拽窗口的大小的
    resize(555,555);

    //设置固定的窗口大小
    setFixedSize(600,400);

    //设置窗口标题
    setWindowTitle("Mrliang");

    //建立一个我本身的按钮
    MyPushButton * mybtn=new MyPushButton;
    mybtn->setText("我本身的按钮");
    mybtn->move(200,200);
    mybtn->setParent(this);//设置到对象树中

    //信号和槽
    //提出需求:点击我本身的按钮 关闭窗口
    //参数1 信号的发送者 参数2 发送的信号(函数的地址) 参数3 信号的接收者 参数4 处理的槽函数

    //j具体实现
    //第一种实现方式
    connect(mybtn,&MyPushButton::clicked,this,&myWidget::close );

    //第二种实现方式
    connect(mybtn,&QPushButton::clicked,this,&QWidget::close);

    //ui->setupUi(this);  //把这行代码注释掉能够自定义窗口title
}


myWidget::~myWidget()
{
   
   
     qDebug()<<"myWidget的析构调用";

    delete ui;
}


达到的效果:此时点击"我本身的按钮“就能够关闭这个窗口
在这里插入图片描述


实现自定义的信号和槽及其重载时的解决方案

添加student类 ,响应teacher的要求:
在这里插入图片描述


此时的widget.cpp

#include "widget.h"
#include "ui_widget.h"

//提出需求
//Teacher 类 老师类
//Student 类 学生类
//下课后 老师会触发一个信号 饿了;学生响应信号 请客吃饭

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
   
   
    ui->setupUi(this);

    //建立老师对象
    this->zl=new Teacher(this);

    //建立学生对象
    this->st=new Student(this);

    //这是没有参数的链接实现
    //实现老师饿了 学生请客的链接 信号和槽的链接
//    connect(zl,&Teacher::hungry,st,&Student::treat);

//    //在类内调用下课的函数
//    classIsOver();


    //当实现有参数的函数重载时的解决方案
    //实现带参数的链接函数 因为设置了函数的重载 这里没法区分究竟是哪一个函数地址 须要建立一个函数指针来指向函数地址
    //建立两个函数指针明确指出指向的是有参数的那个 就不会发生歧义了
    void( Teacher:: *teacherSignal)(QString)= &Teacher::hungry;
    void(Student:: *studentSlot)(QString)=&Student::treat;

    connect(zl,teacherSignal,st,studentSlot);

    classIsOver();
}

//类外实现下课的方法
void Widget::classIsOver()
{
   
   
    //无参数
    //下课函数  调用后 触发老师饿了的信号
    emit zl->hungry();

    //有参数
    emit zl->hungry("宫保鸡丁");
}
Widget::~Widget()
{
   
   
    delete ui;
}



添加的student.h文件和.cpp文件

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
   
   
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);

signals:

public slots:
    //在这里定义一些槽函数 返回值void 须要声明 也须要实现
    //能够有参数 能够发生重载

    void treat();//请客函数

    void treat(QString foodName);//定义函数重载

};

#endif // STUDENT_H


student.cpp

#include "student.h"
#include<QDebug> //输出信号包含的头文件

Student::Student(QObject *parent) : QObject(parent)
{
   
   
}
//在源文件里实现槽函数
void Student::treat()
{
   
   
    qDebug()<<"请老师吃饭";

}
//实现重载的函数
void Student::treat(QString foodName)
{
   
   
    
    qDebug()<<"请老师吃饭 老师要吃:"<< foodName ;//此时的foodName时字符串类型
    //用下面的方式将string 类型转换为char *类型
    qDebug()<<"请老师吃饭,老师要吃:"<<foodName.toUtf8().data();
}


teacher.h

#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
   
   
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);

signals:
    //在这里写自定义的信号
    //无返回值 void 只须要声明 不须要实现
    //能够有参数 能够重载
    void hungry(); //饿了

    void hungry(QString foodName);//信号重载  qt里的字符串:QString

};
#endif // TEACHER_H

teacher.cpp

#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent)
{
   
   

}
//这里不须要实现

实现触发按钮再响应操做:链接与断开链接

主要是在widget.cpp中实现:

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>//按钮类

//提出需求
//Teacher 类 老师类
//Student 类 学生类
//下课后 老师会触发一个信号 饿了;学生响应信号 请客吃饭

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
   
   
    ui->setupUi(this);

    //建立老师对象
    this->zl=new Teacher(this);

    //建立学生对象
    this->st=new Student(this);


    //这是没有参数的链接实现
    //实现老师饿了 学生请客的链接 信号和槽的链接
    //    connect(zl,&Teacher::hungry,st,&Student::treat);

    //    //在类内调用下课的函数
    //    classIsOver();



    //当实现有参数的函数重载时的解决方案
    //实现带参数的链接函数 因为设置了函数的重载 这里没法区分究竟是哪一个函数地址 须要建立一个函数指针来指向函数地址
    //建立两个函数指针明确指出指向的是有参数的那个 就不会发生歧义了
    void( Teacher:: *teacherSignal)(QString)= &Teacher::hungry;
    void(Student:: *studentSlot)(QString)=&Student::treat;

    connect(zl,teacherSignal,st,studentSlot);

    classIsOver();


    //实现点击一个下课的按钮 再触发下课
    QPushButton * btn=new QPushButton("下课",this);
    //重置窗口的大小
    this->resize(600,400);
    //点击按钮  触发下课  实质是信号调用槽函数
    //connect(btn,&QPushButton::clicked,this,&Widget::classIsOver);


    //无参信号和槽链接
    void( Teacher:: *teacherSignal2)(void)= &Teacher::hungry;
    void(Student:: *studentSlot2)(void)=&Student::treat;

    connect(zl,teacherSignal2,st,studentSlot2);

    //实现信号链接信号,中间的信号再链接槽的操做 (按钮点击信号--老师信号--学生请客
    //点击QPushbutton 链接到信号teacherSignal2,而后再链接到槽函数studentSlot2

    connect(btn,&QPushButton::clicked,zl,teacherSignal2);

    //实现断开信号之间的链接 断开老师信号和学生信号之间的链接 那么没法响应最开始按钮的响应了
    disconnect(zl,teacherSignal2,st,studentSlot2);
    
		//补充一些扩展
    
    //1 信号是能够链接信号的
    //2 一个信号能够链接多个槽函数
    //3 多个信号能够链接同一个槽函数
    //4 信号和槽函数的类型一一对应
    //5 信号和槽函数的个数不必定保持一致 信号个数能够比槽函数个数多
            
    //qt4版本以前的信号和槽的链接方式
    //利用qt4信号槽 链接无参版本
    connect(zl,SIGNAL(hungry()),st,SLOT(treat())); 
    //qt4版本的优势是参数直观 缺点是类型不会作检测
    //qt5以上版本 支持qt4的版本写法 反之不支持


//补充关于lambda表达式
    //    []标识符 匿名函数
    //            = 址传递
    //            & 引用传递
    //            ()参数
    //      {}函数实现体
    //             mutable 修饰址传递变量 能够修改拷贝出的数据 可是改变不了主体
    //             返回值 []()->{}
    //用lambda表达式实现 
    //  =是址传递的方式 &是传引用的方式
    
    [=](){
   
   
        btn->setText("aaaa");
    }(); //后面的小括号是调用这个lambda函数

    //若改写如下
    // QPushButton * btn2=new QPushButton;
    //捕获列表[ ]
    [btn]()
    {
   
   
        btn->setText("aa");
        //btn2->setText("bbbb");//此时 btn2是不能被捕捉到的 由于捕捉列表里是btn
    }();

    //    int ret = []()->int{return 1000;}();
    //    qDebug()<<"ret="<<ret;

    //利用lambda表达式 实现点击按钮 关闭窗口.
    QPushButton *btn2=new QPushButton;
    btn2->setText({
   
   "关闭"});
    btn->move(100,0);
    btn2->setParent(this);

    connect(btn2,&QPushButton::clicked,this,[=](){
   
   
//        this->close();//实现关闭窗口
//        emit zl->hungry("宫保鸡丁");
        btn2->setText("aaaa");
    });

}


//类外实现下课的方法
void Widget::classIsOver()
{
   
   
    //无参数
    //下课函数  调用后 触发老师饿了的信号
    emit zl->hungry();

    //有参数
    emit zl->hungry("宫保鸡丁");
}

Widget::~Widget()
{
   
   
    delete ui;
}



信号和槽的机制
在这里插入图片描述


七、补充一下lambda表达式:

Lambda表达式用于定义并建立匿名的函数对象,以简化编程工做。
基本构成:

[capture](parameters) mutable ->return-type
{
   
   
statement
}

函数对象参数 mutable ->返回值{函数体}

① 函数对象参数;
[],标识一个Lambda的开始,这部分必须存在,不能省略。
函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在做用范围内可见的局部变量(包括Lambda所在类的this)。

函数对象参数有如下形式
空。没有使用任何函数对象参数。
=。函数体内可使用Lambda所在做用范围内全部可见的局部变量(包括Lambda所在类的this),而且是值传递方式(至关于编译器自动为咱们按值传递了全部局部变量)。
&。函数体内可使用Lambda所在做用范围内全部可见的局部变量(包括Lambda所在类的this),而且是引用传递方式(至关于编译器自动为咱们按引用传递了全部局部变量)。
this。函数体内可使用Lambda所在类中的成员变量。
a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,由于默认状况下函数是const的。要修改传递进来的a的拷贝,能够添加mutable修饰符。
&a。将a按引用进行传递。
a, &b。将a按值进行传递,b按引用进行传递。
=,&a, &b。除a和b按引用进行传递外,其余参数都按值进行传递。
&, a, b。除a和b按值进行传递外,其余参数都按引用进行传递。

② 操做符重载函数参数
标识重载的()操做符的参数,没有参数时,这部分能够省略。参数能够经过按值(如:(a,b))和按引用(如:(&a,&b)

③ 可修改标示符
mutable声明,这部分能够省略。按值传递函数对象参数时,加上mutable修饰符后,能够修改按值传递进来的拷贝(注意是能修改拷贝,而不是值自己)。

④ 函数返回值
->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器能够自动推断出返回值类型)时,这部分能够省略。
⑤ 是函数体
{},标识函数的实现,这部分不能省略,但函数体能够为空。