Qt基础知识——入门学习笔记

声明

该笔记的内容摘自于传智播客B站视频:https://www.bilibili.com/video/BV1g4411H78N?p=17,只用作自己的学习与分享,侵删。
另外,视频质量很好,推荐一波~

1 Qt概述

1.1 什么是Qt
Qt是一个跨平台的C++图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面所需的所有功能。它是完全面向对象的,很容易扩展,并且允许真正的组件编程。

1.2 Qt的优点

  • 跨平台,几乎支持所有平台
  • 接口简单,容易上手,学习Qt框架对学习其它框架有参考意义
  • 一定程度上简化了内存回收机制
  • 开放效率高,能够快速的构建应用程序
  • 有很好的社区氛围,市场份额在缓慢上升
  • 可以进行嵌入式开发

1.3 成功案例

  • Linux 桌面环境 KDE
  • WPS Office 办公软件
  • Google Earth 谷歌地图
  • VirtualBox 虚拟机软件

2 创建Qt程序

2.1 创建选项
常用默认选项Application:创建一个桌面Qt应用,包含一个基于Qt设计师的主窗体。预选一个可用的Qt桌面版本用于编译程序。
Qt基础知识——入门学习笔记_第1张图片
注意:创建的文件名称不能有中文可以有下划线,路径不能出现中文。
Qt基础知识——入门学习笔记_第2张图片
三大基类:QWidget是QMainWindow和QDialog的父类(继承),QWdiget是空的,QMainWindow多了状态栏,QDialog和对话框有关。
创建界面(Generate form)如果选✔会多出来ui文件,可直接拖拽框架使用。
Qt基础知识——入门学习笔记_第3张图片

2.2 main.cpp

#include "mywidget.h"
#include // 包含一个应用程序类的头文件


//main程序入口  argc命令行变量的数量  argv命令行变量的数组
int main(int argc, char *argv[])
{
    //a应用程序对象,在Qt中,应用程序对象 有且仅有一个
    QApplication a(argc, argv);
    //窗口对象  myWidget父类  -> QWidget
    myWidget w;
    //窗口对象 默认不会显示,必须要调用show方法显示窗口
    w.show();

    //让应用程序对象进入消息循环
    //当代码阻塞到这行
    return a.exec();
	//保证窗口的持续存在,防止一闪而过,直到点击右上角的叉关闭
}

2.3 widget.h

#ifndef WIDGET_H//#ifndef是"if not defined"的简写
#define WIDGET_H//防止头文件重复包含

#include  //包含头文件 QWidget 窗口类

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT // Q_OBJECT宏,允许类中使用信号和槽的机制

public:
    Widget(QWidget *parent = nullptr); //构造函数
    ~Widget(); //析构函数

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

2.4 命名规范

  • 类名 首字母大写,单词和单词之间首字母大写
  • 函数名 变量名称 首字母小写,单词和单词之间首字母大写

2.5 快捷键

  • 注释 ctrl + /
  • 运行 ctrl + r
  • 编译 ctrl + b
  • 字体缩放 ctrl + 鼠标滚轮
  • 查找 ctrl + f
  • 整行移动 ctrl + shift + ↑ 或者↓
  • 帮助文档 F1
  • 自动对齐 ctrl + i;
  • 同名之间的.h 和 .cpp切换 F4

2.6 帮助文档用法

按F1快捷键可找到帮助文档,或者去安装目录里找bin文件,其中也有帮助文档。

主要用于了解类的基本信息:
Qt基础知识——入门学习笔记_第4张图片
下移,找类的使用方法,点进去即可看到详情
Qt基础知识——入门学习笔记_第5张图片

2.6 创建第一个PushButoon

widget.cpp文件

#include "widget.h"
#include 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建一个按钮
    QPushButton * btn = new QPushButton;

    //在帮助文档中可找到父类为QWidget,窗口默认不显示,需要用show方法

    //btn->show(); 直接使用,会出现单独的窗口,而不是出现在主窗口之内
    //需求:让btn对象 依赖在 widget窗口中
    btn->setParent(this);

    //显示文本
    btn->setText("第一个按钮");

    //创建第二个按钮 按照控件的大小创建窗口
    QPushButton * btn2 = new QPushButton;
    btn2->setParent(this);
    btn2->setText("第二个按钮");
    //移动btn2的位置
    btn2->move(150,20);//x,y坐标
    //改变btn2的大小
    btn2->resize(100,70);

    //重置窗口大小
    resize(220,110);//resize(int w,int h):宽,高

    //设置固定的窗口的大小,使得用户无法用鼠标拖拽窗口大小
    setFixedSize(600,400);

    //设置窗口标题
    setWindowTitle("第一个窗口");

}

Widget::~Widget()
{
}


注意:文字不能正常显示的情况,菜单栏找到工具->选项->文本编辑器->行为-> 默认编码,设置为UTF-8即可。

效果展示
Qt基础知识——入门学习笔记_第6张图片

3 对象树

Qt基础知识——入门学习笔记_第7张图片

  • 当创建的对象在堆区的时候,如果指定的父亲是QObject派生下来的类或者其子类派生下来的类,可以不用管释放操作,对象会被放入对象树种
  • 一定程度上简化了内存回收机制。

总的来说:一个parent被析构时,会自动delete/析构它所有的children;一个children被析构时,会自动从他的parent中移除。

4 坐标系

  • Qt坐标系的原点在左上角,X向右增大,Y向下增大;
  • 对于嵌套窗口,其坐标是相对父窗口来说的。

5 信号和槽 *

5.1 样例
信号的英文单词为signal,槽的单词为slot,可以去帮助文档中找相关信息,如果找不到可以去父类中查找。

这里是PushButoon的相关信号:
Qt基础知识——入门学习笔记_第8张图片
用connect函数连接信号和槽

widget.cpp代码如下:

#include "widget.h"
#include 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
   QPushButton * myBtn = new QPushButton;
   myBtn->setText("关闭按钮");
   myBtn->setParent(this);

   //需求 点关闭按钮 关闭窗口
   //参数1 信号的发生者 参数2 发送的信号(函数的地址) 参数3 信号的接收者 参数4 处理的槽函数
   connect(myBtn,&QPushButton::clicked,this,&Widget::close);
}

Widget::~Widget()
{
}


点击按钮即可关闭窗口
Qt基础知识——入门学习笔记_第9张图片
5.2 自定义的信号和槽
建立一个老师类和学生类,自定义信号和槽
首先右键项目 -> Add New… -> 选C++ Class类 -> Base Class 选择 QObject 确认

student.h

#ifndef STUDENT_H
#define STUDENT_H

#include 

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

signals:

public slots:
    //槽函数,早期Qt必须写在public slots下面,高级版本可以写到public或全局下
    //返回值 void , 需要声明, 也需要实现, 可以有参数, 可以发生重载
    void Hello();
};

#endif // STUDENT_H

teacher.h

#ifndef TEACHER_H
#define TEACHER_H

#include 

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

signals:
    //自定义信号写到signals下面
    //规定:返回值是void,只需要声明,不需要实现
    //可以有参数,可以重载
    void StandUp();
};

#endif // TEACHER_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Teacher *ls;
    Student *xs;

    void ClassStart();
};
#endif // WIDGET_H


student.cpp

#include "student.h"
#include 

Student::Student(QObject *parent) : QObject(parent)
{

}

void Student::Hello()
{
    //调试信息直接输出到控制台上
    qDebug()<<"老师好!";
}

widget.cpp

#include "widget.h"
#include 

//Teacher 类 老师类
//Student 类 学生类
//上课铃响 老师会触发一个信号,说起立,学生响应信号,回应老师好

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建一个老师d对象
    this->ls = new Teacher(this);
    //创建一个学生对象
    this->xs = new Student(this);
    //上课铃响,老师喊起立,学生回应老师好
    connect(ls,&Teacher::StandUp,xs,&Student::Hello);

    ClassStart();//注意代码顺序,先连接,再触发才有效
}

void Widget::ClassStart()
{
    //上课,调用后, 老师触发信号
    emit ls->StandUp();
}

Widget::~Widget()
{
}


构建程序的效果:
在这里插入图片描述

5.3 信号和槽重载的解决
在上述程序的基础上,Teacher类的头文件中加上声明 void StandUp(QString sentence); Stuendent类的头文件中加上声明 void Hello(QString sentence),并在cpp文件中写好函数体 qDebug()<<“老师”<

更新widget.cpp文件如下:

#include "widget.h"
#include 

//Teacher 类 老师类
//Student 类 学生类
//上课铃响 老师会触发一个信号,说起立,学生响应信号,回应老师好

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建一个老师d对象
    this->ls = new Teacher(this);
    //创建一个学生对象
    this->xs = new Student(this);
    //上课铃响,老师喊起立,学生回应

    //重载后,编译器不知道选用哪一个函数
    //connect(ls,&Teacher::StandUp,xs,&Student::Hello);发生错误
    //正确方法:函数指针 -> 函数地址

    //声明成员函数的地址,要在前面加上作用域
    void(Teacher::*tearcherSignal)(QString) = &Teacher::StandUp;
    void(Student::*studentSlot)(QString) = &Student::Hello;

    connect(ls,tearcherSignal,xs,studentSlot);

    ClassStart();//注意代码顺序,先连接,再触发才有效
}

void Widget::ClassStart()
{
    //上课,调用后, 老师触发信号
    emit ls->StandUp("威武霸气!");
}

Widget::~Widget()
{
}


效果如下:
在这里插入图片描述
可以看到上述输出sentence的文字,本没有加引号,但是输出了引号。将对应输出改成如下格式即可消去引号。
在这里插入图片描述
5.4 信号连接信号

5.4.1 代码样例

#include "widget.h"
#include 

//Teacher 类 老师类
//Student 类 学生类
//上课铃响 老师会触发一个信号,说起立,学生响应信号,回应老师好

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建一个老师d对象
    this->ls = new Teacher(this);
    //创建一个学生对象
    this->xs = new Student(this);
    //上课铃响,老师喊起立,学生回应

    //点击按钮触发老师的行为
    QPushButton *btn = new QPushButton("上课",this);
    //重置窗口大小
    resize(100,100);
    //无参信号和槽连接
    void(Teacher::*tearcherSignal)(void) = &Teacher::StandUp;
    void(Student::*studentSlot)(void) = &Student::Hello;
    connect(ls,tearcherSignal,xs,studentSlot);
    //信号连接信号
    connect(btn,&QPushButton::clicked,ls,tearcherSignal);
}

void Widget::ClassStart()
{
    //上课,调用后, 老师触发信号
    emit ls->StandUp("威武霸气!");
}

Widget::~Widget()
{
}


运行后点击按钮即可触发对应函数可直接触发老师类的StandUp,再触发学生类的Hello。

5.4.2 拓展

  • 断开信号可以用disconnect函数,参数与connect函数中的一样。
  • 一个信号可以连接多个槽函数
  • 多个信号可以连接同一个槽函数
  • 信号和槽函数的参数 必须类型一一对应
  • 信号的参数个数 可以多余 槽的参数个数
  • Qt4版本信号槽连接:connect(发送者,SIGNAL(信号函数),接收者,SLOT(槽函数));
  • Qt4版本优点:参数直观;缺点:类型不做检测

6 Lambda表达式

6.1 介绍
C++11 中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。
-基本构成:

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

[函数对象参数](操作符重载函数参数)mutable->返回值(函数体)

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

Qt基础知识——入门学习笔记_第10张图片
② 操作符重载函数参数
标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。

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

④ 函数返回值
->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

⑤ 函数体
{},标号函数的实现,这部分不能省略,但函数体可以为空。

6.2 试用样例

#include "widget.h"
#include 
#include 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QPushButton * btn = new QPushButton;
    btn->setParent(this);
    btn->show();

    int m = 10;
    connect(btn,&QPushButton::clicked,this,[m]()mutable{
        m= 10+100;
        qDebug()<<m;
    });
    connect(btn,&QPushButton::clicked,this,[m](){
        qDebug()<<m;
    });
    int k = 1000;
    int ret = [=]()->int{return k;}();//后面加括号调用函数
    qDebug()<<ret;
}

Widget::~Widget()
{
}


先输出1000,然后每次点击按钮会输出110和10。
注意:在上述代码中按钮连接的lambda表达式中不能用k值,因为不在作用域内;如果lambda第三个参数是this可以省略该参数。

lambda表达 最常用:[=](){}

7 小作业

要求实现:一个按钮开始显示“Open",点击Open打开窗口并且显示改为"Close",点击Close又会关闭打开的窗口,并且文本变回"Open”。

代码如下:

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{

    QPushButton * btn = new QPushButton("Open",this);
    btn->show();
    QWindow * myWindow = new QWindow;
    bool flag = false;
    connect(btn,&QPushButton::clicked,[=]()mutable{
        if(!flag){
            btn->setText("Close");
            myWindow->show();
        }else{
            btn->setText("Open");
            myWindow->close();
        }
        flag = !flag;
    });
}

Widget::~Widget()
{
}


你可能感兴趣的:(QT)