文章目录

  • 1、Qt 概述:
  • (1)windoes 平台 Qt 的下载与安装:
  • 2、Qt 的项目结构
  • (1)qt 程序的入口 main.cpp
  • (2)mywindow.h 头文件
  • (3)mywindow.cpp 构造函数 MyWindow() 和 析构函数 ~MyWindow() 所在的文件
  • (4)qt creator 快捷键
  • 3、Qt 的信号 与 槽
  • (1)Qt 中的信号与槽连接模型
  • (2)创建信号与槽
  • (3)自定义信号与槽
  • 4、不使用ui文件编程,以按钮为例(设置按钮的文本,按钮的位置,按钮的大小,主窗口的大小,来完成界面的设计)
  • 5、Qt 的 Object Tree (对象树)
  • (1)Qt 为什么需要设置父对象:设置父对象的主要目的是管理子对象的生命周期和管理子对象的内存;
  • (2)如何设置父对象
  • (3)Qt 的对象树机制
  • 6、Qt 项目添加资源文件
  • 7、Qt样式表,Qt Style Sheet(qss)
  • 7、Qt C++,QML,Qt Quick 是什么,区别和联系
  • 8、Qt 控件入门
  • 9、Qt 常用类
  • 10、margin 和 padding(外边距和内边距)


1、Qt 概述:

Qt是一个用C++编写的、跨平台的GUI工具包

(1)windoes 平台 Qt 的下载与安装:

Qt 5.15之前的版本可以离线安装,直接下载离线安装包即可

下载地址:https://download.qt.io/archive/qt/

Qt从5.15开始,不再支持离线安装,那我们就需要下载 Qt 在线安装器,安装Qt

Qt 在线安装器下载地址:https://download.qt.io/official_releases/online_installers/
2、Qt 的项目结构
untitled
	|____untitled.pro    ---- qmake工程文件(如果选择cmake则工程文件为CMakeLists.txt)
	|____头文件
	|        |____mywindow.h
	|____源文件
	|	    |____main.cpp	  ---- 程序的入口
	|	    |____mywindow.cpp	  
	|____界面文件
		    |____mywindow.ui      ---- ui类
(1)qt 程序的入口 main.cpp
#include "mywindow.h"
#include <QApplication>

// argc 是命令行参数个数,argv是命令行参数
int main(int argc, char *argv[])
{
    // QApplication app(argc, argv) 管理Qt程序的运行,设置Qt应用程序,针对QWidget应用程序;
    // QGuilication app(argc, argv) 管理Qt程序的运行,设置Qt应用程序,针对非QWidget应用程序,比如QQuick;
    // QCorelication app(argc, argv) 管理Qt程序的运行,设置Qt应用程序,针对无界面的应用程序;
    QApplication app(argc, argv);
  
    // MyWindow是我们自定义的类,w是创建的对象;
    MyWindow w;
    // w对象调用了show() 方法;
    w.show();
    // 事件循环,QEventLoop::exec(),等待鼠标或键盘等其他的输入;
    return app.exec();
}
(2)mywindow.h 头文件
#ifndef MYWINDOW_H
#define MYWINDOW_H

#include <QMainWindow>

// 命名空间
QT_BEGIN_NAMESPACE
namespace Ui { class MyWindow; }
QT_END_NAMESPACE

// 自定义类MyWindow 公有继承 QMainWindow类
class MyWindow : public QMainWindow
{
    // 宏定义,Qt信号槽
    Q_OBJECT

public:
    // 构造函数,MyWindow 是构造函数名,QWidget *parent 是构造函数的参数,= nullptr 表示该参数有一个默认值为 nullptr,即可以不传入该参数
    // QWidget *parent 参数表示父窗口的指针,即在创建 MyWindow 对象时,需要传入一个 QWidget 对象的指针作为父窗口,如果没有父窗口,则传入 nullptr,表示当前窗口是主窗口(即顶层窗口)
    MyWindow(QWidget *parent = nullptr);
    // 析构函数,在对象销毁前系统自动调用,执行一些清理工作
    ~MyWindow();
    // 添加一个自己的变量,声明一个变量
    int i;

private:
    // 创建一个 Ui::MyWindow 类对象指针 *ui( 该指针指向一个自动生成的 Ui类对象,这个 Ui类对象 就是mywindow.ui文件对象 )
    Ui::MyWindow *ui;
};
#endif // MYWINDOW_H
(3)mywindow.cpp 构造函数 MyWindow() 和 析构函数 ~MyWindow() 所在的文件
#include "mywindow.h"
#include "ui_mywindow.h"
#include <QDebug>		// QDebug 可以打印输出调试信息
// 定义了一个对象 QWidget *parent
// 把定义的对象parent,交给QMainWindow(),初始化出一个 继承了QWidget 的 QMainWindow对象
// 在构造函数里初始化对象要写在冒号 : 之后
MyWindow::MyWindow(QWidget *parent)
    : QMainWindow(parent)       // 初始化 QMainWindow 对象
    , ui(new Ui::MyWindow)	// 写法等同于,ui = new Ui::MyWindow(创建一个 Ui::MyWindow 类对象,并将其指针赋值给 ui,ui指针指向一个自动生成的 Ui类对象,这个 Ui类对象 就是mywindow.ui文件对象)
    , i(4)    			   // 初始化自定义变量i,写法等同于,i=4
{
    // 初始化自定义变量i,也可以写在这里,在上面已经写过了,这里就先注释掉
    // i=4  
    // 调用 setupUi() 函数,是为了将,当前窗口对象(MyWindow 类的对象),和由 Qt Designer 工具生成的 mywindow.ui文件关联起来,并将 mywindow.ui文件中定义的部件集成到,当前窗口对象(MyWindow 类的对象)中,从而实现,当前窗口对象,与mywindow.ui文件的显示和交互,即所谓的窗口部件化;
    ui->setupUi(this);
    // ui指针指向一个自动生成的 Ui类对象,这个 Ui类对象 就是mywindow.ui文件对象 
    // this 在这里代表当前窗口对象,也就是 MyWindow 类的对象
    // 打印输出调试信息
    qDebug() << "构造函数执行了!" << endl;
}

MyWindow::~MyWindow()
{
    // 打印输出调试信息
    qDebug() << "析构函数执行了!" << endl;  
    // 销毁
    delete ui;
}
(4)qt creator 快捷键
Ctrl + R 	       运行
Ctrl + Shift + Enter  上一行
Ctrl + Enter          下一行
选中类名 + F1          打开帮助文档
3、Qt 的信号 与 槽

信号与槽(Signal & Slot)是 Qt 编程的基础,也是Qt的一大创新。因为有了信号与槽的编程机制,在Qt中处理界面各个组件的交互操作时变得更加直观和简单;

GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理的去响应和处理这些信号就可以了。

(1)Qt 中的信号与槽连接模型

发送者 -> 信号 -> 接收者-> 槽

对象 -> 函数 -> 对象 -> 函数

信号与槽的连接:

举个例子:我们要实现点击按钮关闭窗口,按钮(对象) -> 点击函数(信号) -> 主窗口(对象) -> 关闭函数(槽)

  • 信号(Signal):在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的CurrentIndexChanged() 信号;
  • 槽(Slot):就是对信号响应的函数。槽就是一个函数,与一般的C++ 函数是一样的,可以定义在类的任何部分(public,private,protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是,槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
  • 信号与槽关联:用 QObject::connect() 函数实现的,其基本格式为:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

connect() 是 QObject 类的一个静态函数,而 QObject 是所有 Qt 类的基类,在实际调用时可以忽略前面的限定符,所以可以直接写为:

connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
  • sender 是发射信号的对象的名称;
  • signal() 是信号名称;信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数;
  • receiver 是接收信号的对象名称;
  • slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数;
  • SIGNAL 和 SLOT 是Qt的宏,用于指明信号和槽,并将他们的参数转换为相应的字符串。

一个信号可以连接多个槽(当一个对象pushButton被点击时,有两个槽响应,hide()隐藏窗体,close()关闭窗体)

  • connect(pushButton, SIGNAL(clicked()), this, SLOT(hide()));
  • connect(pushButton, SIGNAL(clicked()), this, SLOT(close()));

多个信号可以连接同一个槽

  • connect(pushButton1, SIGNAL(clicked()), this, SLOT(close()));
  • connect(pushButton2, SIGNAL(clicked()), this, SLOT(close()));

一个信号可以连接到另外一个信号

  • 信号与槽断开连接:disconnect()
bool QObject::disconnect(const QObject *sebder, const char *singnal, const QObject *receiver, const char *method)
  1. 断开所有与 myObject 连接的信号或槽:disconnect(myObject, 0, 0, 0) 等价于 myObject -> disconnect();
  2. 断开所有连接到特定信号的连接:disconnect(myObject, SIGNAL(mySignal()), 0, 0) 等价于 myObject->disconnect(SIGNAL(mySignal());
  3. 与指定的接收者断开连接:disconnect(myObject, 0, SLOT(slot()), 0) 等价于 myObject -> disconnect(SLOT(slot()));
(2)创建信号与槽

方法一:通过GUI方式:

双击 mainwindow.ui 文件 -> 拖拽 PushButton -> 点击信号与槽 -> 添加(发送者,信号,接收者,槽) -> 运行查看效果

方法二:通过代码方式添加:

打开 mainwindow.cpp 文件,通过代码添加信号与槽:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 在这里添加信号与槽 pushButton按钮对象,clicked()点击信号,this接收对象,主窗口MainWindow,close()槽函数
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close()));
}

MainWindow::~MainWindow()
{
    delete ui;
}
(3)自定义信号与槽

例子:学校 -> 通知 -> 学生 -> 上课

我们需要建一个学校类(发送者),建一个学生类(接收者),建一个通知函数(信号),建一个上课函数(槽)

新建一个学校类

#ifndef SCHOOL_H
#define SCHOOL_H

#include <QObject>

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

signals:    // Qt信号的关键字
    // 1、信号函数声明
    void sendMessage();

};

#endif // SCHOOL_H

新建一个学生类

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

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

signals:

// 2、槽函数声明
public slots:
    void comBackStudy();

};

#endif // STUDENT_H

在界面类的头文件中引入学校类和学生类

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
// 3、在界面类的头文件中引入学校类和学生类
#include "school.h"
#include "student.h"

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

// 4、声明School类和Student类
class School;
class Student;

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    // 5、创建School类的对象,创建Student类的对象,写在这里是公有的,写在下面是私有的
    School *school;
    Student *student;

private:
    Ui::MainWindow *ui;

};
#endif // MAINWINDOW_H

在界面类的构造函数里,实例化School类和Student类

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //6、在界面类的构造函数里,实例化School类和Student类
    school = new School(this);
    student = new Student(this);

    // 7、添加信号与槽
    connect(school, SIGNAL(sendMessage()), student, SLOT(comBackStudy()));
    // 9、当MainWindow类执行完,发送一个sendMessage()的信号
    emit school->sendMessage();

}

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

槽函数定义

#include "student.h"
#include <QDebug>

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

}

// 8、槽函数定义
void Student::comBackStudy()
{
    qDebug() << "学生上课!" << endl;
}

完成

4、不使用ui文件编程,以按钮为例(设置按钮的文本,按钮的位置,按钮的大小,主窗口的大小,来完成界面的设计)

主窗口的头文件引入QPushButton

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
// 1、主窗口的头文件引入QPushButton
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    // 3、声明一个按钮对象pushButton
    QPushButton *pushButton;
};
#endif // MAINWINDOW_H

项目文件这里加 widgets

QT       += core gui

# 2、项目文件这里加 widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

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 \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

实例化pushButton按钮

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // 4、实例化pushButton按钮
    pushButton = new QPushButton(this);
    // 设置按钮的文本
    pushButton->setText("我是个按钮");
    // 按钮的位置,按钮的大小
    pushButton->setGeometry(0, 0, 100, 40);
    // 主窗口的大小
    this->resize(800, 480);
    // 搞一个信号槽试试
    connect(pushButton, SIGNAL(clicked()), this, SLOT(close()));
}

MainWindow::~MainWindow()
{
}
5、Qt 的 Object Tree (对象树)
(1)Qt 为什么需要设置父对象:设置父对象的主要目的是管理子对象的生命周期和管理子对象的内存;
  • 父对象在析构的时候,会连带子对象全部释放,避免内存泄漏;
  • 父对象显示的时候,子对象也会自动显示,不需要单独调用 show 方法,方便管理界面元素;
  • 父对象可以通过子对象列表访问和操作子对象,实现对象间的通信和协作;
(2)如何设置父对象
  • 通过构造函数传参
  • 通过 setParent() 方法
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 通过构造函数传参
    // pushButton = new QPushButton(this);

    // 通过 setParent() 方法
    pushButton = new QPushButton;
    pushButton->setParent(this);

}

Widget::~Widget()
{
}
(3)Qt 的对象树机制

在 Qt 中,使用对象树(object tree)来组织和管理所有的 QObject 类及其子类的对象。当创建一个 QObject 时,如果使用了其他的对象作为其父对象(parent),那么这个 QObject 就会被添加到父对象的 children() 列表中,这样当父对象被销毁时,这个 QObject 也会被销毁。

(4)QObject 基类

QObject 是所有 Qt 对象的基类,QObject 类集成了 Qt 元对象系统,实现了标准 C++ 对象模型没有提供的功能,从而实现了一系列便于用户开发使用的功能;

6、Qt 项目添加资源文件

1、将资源文件logo.png复制到项目文件夹中;

2、右键项目名 -> 添加新文件 -> 选择Qt -> Qt Resource File -> 输入名称resources -> 点击完成 -> 项目会多出一个资源文件resources.qrc;

3、右键resources.qrc文件 -> 选择Open in Editor -> 在资源编辑器中 -> 添加前缀(比如 / 或 /image) -> 添加文件选择需要添加的资源文件logo.png -> 完成;

4、你可以在代码中使用“:”+前缀+logo.png的格式来引用资源文件,比如“:/image/logo.png”

7、Qt样式表,Qt Style Sheet(qss)

QSS 是 Qt Style Sheets 的缩写,是 Qt 提供的一种用来自定义控件外观的机制,类似于 HTML 中的 CSS,QSS 的语法规则与 CSS 类似,但是功能比 CSS 弱很多,选择器和属性都比较有限。要使用 QSS,有以下几种方法:

  • 在 Qt Designer 中设置每个控件的 styleSheet 属性;
    双击 mainwindow.ui 文件 -> 添加一个QLable组件 -> 右键改变样式表样式 -> 添加资源文件图片 -> 运行查看效果
QLabel {
     border-image: url(:图片资源地址);
}
  • 在代码中调用控件的 setStyleSheet() 接口来设置样式;
this -> setStyleSheet(" QWidget { background-color:blue } ");
  • 将 QSS 内容保存到文件中,通过代码读取该文件内容;

举例说明,如果要设置 QPushButton 的样式,可以这样写:

(1)右键项目名 -> 添加新文件 -> 选择Qt -> Qt Resource File -> 输入名称resources -> 点击完成 -> 项目会多出一个资源文件resources.qrc;

(2)右键resources.qrc文件 -> 选择Open in Editor -> 在资源编辑器中 -> 添加前缀(比如 / ) -> ctrl+s保存;

(3)右键resources.qrc文件 -> 添加新文件 -> 选择Qt -> Qt Resource File -> 输入文件名 style.qss -> 点击完成 -> 项目会多出一个资源文件style.qss -> 我们可以在这个文件中定义控件的样式;

QPushButton {
  color: red; /* 设置文字颜色为红色 */
  background-color: white; /* 设置背景颜色为白色 */
  font: bold; /* 设置字体为粗体 */
}

QPushButton:hover {
  background-color: gray; /* 设置鼠标悬停时的背景颜色为灰色 */
}

QPushButton:pressed {
  background-color: black; /* 设置鼠标按下时的背景颜色为黑色 */
}

(4)在QPushButton控件显示之前引用,我们放到main.cpp文件中

#include "mainwindow.h"

#include <QApplication>
#include <QFile>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // 引入qss文件
    QFile file(":/style.qss");
    if ( file.exists() ) {
        // 以只读的方式打开
        file.open(QFile::ReadOnly);
        // 以字符串的方式保存读出的结果
        QString styleSheet = QLatin1String(file.readAll());
        // 设置全局样式
        qApp->setStyleSheet(styleSheet);
        // 关闭文件
        file.close();
    }
    MainWindow w;
    w.show();
    return a.exec();
}
7、Qt C++,QML,Qt Quick 是什么,区别和联系

Qt C++,QML,Qt Quick 是Qt框架中的不同技术,Qt C++ 是用于实现逻辑和数据的技术,而 QML 和 Qt Quick 是用于创建 GUI 的技术,它们可以相互配合,也可以单独使用,根据不同的需求和场景,开发者可以选择合适的技术来开发 Qt 应用程序;

  • Qt C++ 是一个基于 C++ 的应用程序框架,它提供了一系列的 C++ 类库,用于实现 GUI、网络通信、数据库访问、多媒体处理等功能,Qt C++ 还支持元对象系统、信号和槽机制、模型视图架构等特性,Qt C++ 的优点包括高性能、稳定性、兼容性等;
  • Qt Modeling Language(QML)是一种声明式语言,用于创建动态的 GUI,QML 采用 JSON 风格的语法,可以定义 UI 元素的属性、布局、行为、动画等,QML 还可以和 C++ 或其他语言进行交互,实现逻辑和数据的处理,QML 的优点包括简洁、灵活、可重用等;
  • Qt Quick 是一个基于 QML 的应用程序框架,它提供了一系列的 QML 类型,用于创建高性能、流畅、响应式的 GUI,Qt Quick 还支持 OpenGL ES 渲染、粒子系统、着色器效果等高级功能,Qt Quick 的优点包括跨平台、易扩展、丰富的文档和示例等;
8、Qt 控件入门

请看我的另一篇博客:Qt 常用控件及信号

9、Qt 常用类

请看我的另一篇博客:Qt 常用类总结

10、margin 和 padding(外边距和内边距)
  • margin:一个控件的边框到另一个控件的边框的距离,属于容器外部距离;
  • padding:自身边框到自身内部另一个容器边框之间的距离,属于容器内距离;