QT——C++ GUI开发01

一、 QT介绍

参考1
参考2

QT快速入门教程

Qt(官方发音 [kju:t],音同 cute)是一个跨平台的 C++ 开发库,主要用来开发图形用户界面(Graphical User Interface,GUI)程序,当然也可以开发不带界面的命令行(Command User Interface,CUI)程序。

Qt4 时代的主流就是传统部件(或叫控件)编程,所用的语言一般是 C++。 Qt5 诞生之时,正是手机移动设备蓬勃发展的时候,而传统的 C++ 部件编写的界面对手机应用程序非常方便,比如手机屏幕显示随意翻转, 这在传统桌面程序里基本遇不到,谁会将 22 寸显示器翻过来转过去呢。

为了适应手机移动应用开发, Qt5 将 QML 脚本编程提到与传统 C++ 部件编程相同的高度,力推 QML 界面编程,当然 QML 主要用于手机移动应用程序。 QML 包含大量使用手机移动设备的功能模块,比如基本部件(QtQuick 模块)、GPS 定位、渲染特效、蓝牙、NFC、WebkKit 等等。

时代在变化,C++ 标准也在前进。C++ 正式公布标准有 C++98、C++03、C++11。最新的 C++11 标准是2011年8月12日公布的,在公布之前该标准原名为 C++0x 。这是一次较大的修订和扩充,建议读者专门学一下。

Qt 从 4.8 版本就开始用 C++11 新特性了。编译器里面开始支持 C++11 的版本是 MSVC 2010、GCC 4.5、Clang 3.1,这之后版本的编译器都在逐步完善对 C++11 的支持,现在新版本编译器对新标准的支持都比较全面了。

Qt 官方在编译 Qt5 库的时候都是开启 C++11 特性的,如果我们要在自己项目代码启用新标准,需要在 .pro 文件里面添加一行:

(一)下载安装

下载地址

对目录结构的说明
目录 说明
archive 各种 Qt 开发工具安装包,新旧都有(可以下载 Qt 开发环境和源代码)。
community_releases 社区定制的 Qt 库,Tizen 版 Qt 以及 Qt 附加源码包。
development_releases 开发版,有新的和旧的不稳定版本,在 Qt 开发过程中的非正式版本。
learning 有学习 Qt 的文档教程和示范视频。
ministro 迷你版,目前是针对 Android 的版本。
official_releases 正式发布版,是与开发版相对的稳定版 Qt 库和开发工具(可以下载Qt开发环境和源代码)。
online Qt 在线安装源。
snapshots 预览版,最新的开发测试中的 Qt 库和开发工具。

安装教程

  1. 安装好qt后,配置两个环境变量
//换成自己的安装目录
D:\it\qt5.9.8\5.9.8\mingw53_32\bin
D:\it\qt5.9.8\Tools\mingw530_32\bin
  1. 安装cmake
    参考

在这里插入图片描述

  1. 配置cmake
    在这里插入图片描述

在这里插入图片描述

安装好后,在win开始页面会有很多应用。介绍如下:

对各个程序的说明
程序 说明
Qt Creator 4.6.2 (Enterprise) Qt 的集成开发环境,本教程就使用它来创建和管理 Qt 项目。
Assistant(Qt 助手) 用来查看帮助文档,已被集成在 Qt Creator 中。
Designer(Qt 设计师) 图形界面可视化编辑工具,已被集成在 Qt Creator 中,在 Qt Creator 中编辑或创建界面文件时,就可以自动打开。
Linguist(Qt 语言家) 多国语言翻译支持工具,可以用来编辑语言资源文件,在开发多语言界面的应用程序时会用到。
Qt 5.11.1 for Desktop (MinGW 5.3.0 32bit) Qt 命令行工具,用来配置 Qt 开发环境(主要是设置 PATH 变量)。

找到Qt Creator 并打开。

(二)集成开发环境Qt Creator使用

Qt Creator可视化页面介绍

参考

  1. 打开是这个样子
    在这里插入图片描述
    在这里插入图片描述

二、hello world

(一)新建项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(二)打印hello world

qt 框架封装了打印日志的方法,在QDebug类中。使用方法跟cout类似。

  • mainwindow.cpp 。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug> //导入日志包

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    //这个表示对属性ui进行初始化 初始值为:new Ui::MainWindow。用逗号分割,后面可以初始化很多属性
    ui(new Ui::MainWindow)
{
    // 将 mainwindow.ui 的实例对象和 当前类的对象进行关联(解析 mainwindow.ui),将这个代码放最前面
    ui->setupUi(this);
    //其他组件和业务代码

    //一共有四种日志级别。
    qDebug()<< "hello world!"<<"——————debug级别。"; //注意是qDebug() ,不是qDebug
    qWarning() << "Warning:" << "错误级别。";
    qInfo() << "qInfo:"  << "正常输出级别。";
    qCritical() << "qCritical:" ;

}

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

在这里插入图片描述
当更改代码后需要重新构建项目,代码才会是生效。

  • 输出
    在这里插入图片描述

(三)使用Qt Creator查看文档

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

需要哪个方法就点进去看,看不懂可以去翻译一下。

三、qt提供的数据类型

(一)字符串

  1. QByteArray
  2. QString
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QByteArray> // 导入字符串
#include <QString>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    // 将 mainwindow.ui 的实例对象和 当前类的对象进行关联(解析 mainwindow.ui),将这个代码放最前面
    ui->setupUi(this);
    //其他组件和业务代码
    // 使用无参构造创建一个类
    QByteArray s;
    s.append("lihua");
    qDebug()<<s;

    QByteArray s1("my name is ");
    s1.append("lihua");
    qDebug()<<s1;

    QString str("123");
    str.append("-456");
     qDebug()<<str;
}

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

(二)坐标QPoint

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPoint>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创建一个坐标点A,并调用方法设置坐标点的x、y轴
    QPoint pointA;
    pointA.setX(10);
    pointA.setY(20);

    //调用有参构造器创建一个坐标点
    QPoint pointB(40,80);

    //无参构造器默认x、y轴为(0,0)
    QPoint pointC;

    //获取坐标点的x、y轴的值。
    qDebug()<< pointA.x();
    qDebug()<< pointB.y();
    qDebug()<<"x=" <<pointC.x()<<"y="<<pointC.y();
}

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

(三)直线QLine

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPoint> //坐标
#include <QDebug>
#include <QLine> //直线,由两个坐标点构成

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创建一个坐标点A,并调用方法设置坐标点的x、y轴
    QPoint pointA;
    pointA.setX(10);
    pointA.setY(20);

    //调用有参构造器创建一个坐标点
    QPoint pointB(40,80);

    //无参构造器默认x、y轴为(0,0)
    QPoint pointC;

    //获取坐标点的x、y轴的值。
    qDebug()<< pointA.x();
    qDebug()<< pointB.y();
    qDebug()<<"x=" <<pointC.x()<<"y="<<pointC.y();



    //QLine()
    //QLine(const QPoint &p1, const QPoint &p2)
    //QLine(int x1, int y1, int x2, int y2)

    QLine line(pointC,pointA);
    qDebug() << "直线的中点"<<line.center().x()<<","<<line.center().y();
    

}

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

(四)形容二维对象的大小QSize

QSize类使用整数点精度定义二维对象的大小。

尺寸由宽度()和高度()指定。它可以在构造函数中设置,并使用setWidth()、setHeight()或scale()函数或算术运算符进行更改。还可以通过使用rwidth()和rheight()函数检索对宽度和高度的引用来直接操作大小。最后,可以使用transpare()函数交换宽度和高度。

isValid()函数确定大小是否有效(有效大小的宽度和高度均大于或等于零)。如果宽度和高度中的任何一个小于或等于零,isEmpty()函数将返回true,而只有当宽度和高度都为零时,isNull()函数才返回true。

使用expandedTo()函数检索一个大小,该大小包含此大小和给定大小的最大高度和宽度。类似地,boundedTo()函数返回一个大小,该大小包含此大小和给定大小的最小高度和宽度。

QSize对象可以流式传输,也可以进行比较。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QSize> // QSize 类用来形容长度和宽度

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    //QSize 类用来形容长度和宽度
    QSize size(10,19);
    //交换宽和高,并返回他们交换后的值
    QSize sizeTran =  size.transposed();
    qDebug()<<sizeTran.width();
    qDebug()<<sizeTran.height();

}

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

(五)矩形QRect

QRect类使用整数精度定义平面中的矩形。矩形通常表示为左上角和一个大小。QRect的大小(宽和高)总是等价于数学矩形,构成了它的渲染基础。 QRect可以用一组左、上、宽、高整数来构造,也可以用一个QPoint和一个QSize来构造。

  • 两种构建方式:

QRect r1(100, 200, 11, 16);
QRect r2(QPoint(100, 200), QSize(11, 16));

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void paintEvent(QPaintEvent *);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPoint> //坐标
#include <QDebug>
#include <QLine> //直线,由两个坐标点构成
#include <QSize> // QSize 类用来形容长度和宽度
#include <QPainter> //画家类

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

void MainWindow::paintEvent(QPaintEvent *){

    //创建一个坐标点A,并调用方法设置坐标点的x、y轴
    QPoint pointA;
    pointA.setX(10);
    pointA.setY(20);

    //调用有参构造器创建一个坐标点
    QPoint pointB(40,80);

    //无参构造器默认x、y轴为(0,0)
    QPoint pointC;

    //获取坐标点的x、y轴的值。
    qDebug()<< pointA.x();
    qDebug()<< pointB.y();
    qDebug()<<"x=" <<pointC.x()<<"y="<<pointC.y();



    //QLine()
    //QLine(const QPoint &p1, const QPoint &p2)
    //QLine(int x1, int y1, int x2, int y2)

    QLine line(pointC,pointA);
    qDebug() << "直线的中点"<<line.center().x()<<","<<line.center().y();

    //QSize 类用来形容长度和宽度
    QSize size(200,120);
    //交换宽和高,并返回他们交换后的值
    QSize sizeTran =  size.transposed();
    qDebug()<<sizeTran.width();
    qDebug()<<sizeTran.height();


    QRect rect(pointA,size);


    //实例化画家对象  this指定的是绘图设备
    QPainter painter(this);

    //设置画笔
    QPen pen(QColor(255,0,0));
    //设置画笔宽度
    pen.setWidth(3);
    //设置画笔风格
    pen.setStyle(Qt::DotLine);
    //让画家 使用这个笔
    painter.setPen(pen);


    //设置画刷
    QBrush brush(Qt::cyan);
    //设置画刷风格
    brush.setStyle(Qt::Dense7Pattern);
    //让画家使用画刷
    painter.setBrush(brush);

    //画矩形
    painter.drawRect(rect);
}

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

(六)时间QDate、QTime、QDateTime

//时间
void MainWindow::dateTest(){
    //获取空日期对象,没有办法直接使用,需要自己添加日期
    QDate date1;
    date1.setDate(2022,10,12);
    //在日期的基础上增加12天
    QDate date3 = date1.addDays(12);
    //通过有参构造器获取日期对象
    QDate date2(2022,10,10);

    //通过方法获取当前日期对象
    QDate nowDate = QDate::currentDate();

    //日期格式化输出
    QString dateStr =  nowDate.toString("yyyy-M-dd");


    qDebug()<< date1;
    qDebug()<< date3;
    qDebug()<< date2;
    qDebug()<< nowDate;
    qDebug()<< dateStr;

    //获取时间对象,h must be in the range 0 to 23, m and s must be in the range 0 to 59, and ms must be in the range 0 to 999.
    QTime time(12,22,22,999);

    //获取当前时间
    QTime nowTime = QTime::currentTime();

    qDebug()<<time;
    qDebug()<<nowTime;
    //格式化输出
    qDebug()<<nowTime.toString("hh:mm:ss");

    //获取日期+时间
    QDateTime dateTime(QDate::currentDate(),QTime::currentTime());

    qDebug()<<dateTime;


    //格式化输出
    qDebug()<<dateTime.toString("yyyy-MM-dd hh:mm:ss");

    //获取时间戳,单位毫秒
    qDebug()<< QDateTime::currentMSecsSinceEpoch();
    //获取时间戳,单位秒
    qDebug()<< QDateTime::currentSecsSinceEpoch();

}

四、信号\槽

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式 (发布 - 订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QTextEdit>
#include <QDebug>

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

    //创建一个按钮
    QPushButton * btn = new QPushButton("get_name",this);
    btn->move(10,40);
    //一个文本输入框
    QTextEdit *textName = new QTextEdit("getName",this);
    textName->move(10,100);

    //为按钮添加一个点击(鼠标点击一次就是信号)事件(点击鼠标后触发的事件就是槽),下面的是Lambda表达式
    connect(btn,&QPushButton::clicked,textName,[=](){
        qDebug()<<"ok";
        textName->setText("lihua");
    });
}

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

信号和槽机制其实就是发布订阅模式。

  1. 订阅一个信号:connect(this,&MainWindow::signalMain,thread,&MyWork::slotWork);连接函数就相当于订阅操作,订阅了这个信号signalMain 。
  2. 生产者发布一个信号(注意:这个发布的信号是一次性的,调用一次emit ,就发送一个。同时已经订阅了这个信号的消费者才会接受到这个信号,也就是先订阅再发布信号) emit signalMain(10); 发送信号的时候也可以传递一些参数给回调函数。比如这里的10。
  3. 消费者接收到这个信号,调用回调函数(槽函数)。消费者如何接收到信号的,这个是由qt框架实现的。回调函数(槽函数)&MyWork::slotWork

一个向子线程传递参数的例子:

  • mywork.h
#ifndef MYWORK_H
#define MYWORK_H

#include <QObject>
#include <QThread>

/**
 *    @class   mywork.h
 *
 *    @brief   工作线程
 *
 *
 *    @author:   lihua
 *    @date:     2022-10-25  15:53
 */
class MyWork : public QThread
{
    Q_OBJECT
public:
    explicit MyWork(QThread *parent = nullptr);

signals:
    //信号由子线程发出,主线程接收(子线程返回执行结果给主线程)
    void signalWork(int result);

public slots:
    //信号由主线程发出,子线程接收(主线程传入参数给子线程)
    void slotWork(int num);

    // QThread interface
protected:
    void run();

private:
    int num = 0;

};

#endif // MYWORK_H

  • mywork.cpp
#include "mywork.h"
#include <QDebug>

MyWork::MyWork(QThread *parent) : QThread(parent)
{

}

void MyWork::slotWork(int num)
{
    //调用槽函数
    qDebug()<< "子线程的槽函数被调用"<<num;
    this->num = num;

}

/**
 * @brief 主线程传一个初始值num给子线程,子线程在num的基础上加100
 *
 * @param  run没有参数,num是通过槽函数获取的
 *
 * @return  run没有返回值将计算结果通过槽函数返回给主线程
 */
void MyWork::run()
{

    qDebug()<< "运行子线程<<" << QThread::currentThread();

    //主线程给一个初始值num
    int num = this->num;



    int result = num +100;

    //发出信号,订阅了此信号的订阅者的槽函数会被回调,将计算结果通过槽函数返回给主线程
    qDebug()<< "结果:"<<result;
    emit signalWork(result);


}

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "mywork.h"

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    //子线程
    MyWork *thread;

    // 计算结果
    int result;

signals:
    //信号
    void signalMain(int num);

public slots:
    //槽函数
    void slotMain(int result);

};



#endif // MAINWINDOW_H

  • mainwindow.cpp
#include "mainwindow.h"
#include "mywork.h"
#include "ui_mainwindow.h"

#include <QThread>
#include <QDebug>

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

    qDebug()<< QThread::currentThread();

    thread = new MyWork();


    //订阅signalMain信号,并指定回调函数。
    connect(this,&MainWindow::signalMain,thread,&MyWork::slotWork);

    //订阅signalWork信号,并指定回调函数
    //connect(thread,&MyWork::signalWork,this,&MainWindow::slotMain); 也可以用lamda实现
    connect(thread,&MyWork::signalWork,this,[=](int result){

        this->result = result;
        qDebug()<< "result="<<this->result;
    });

    //发出一个信号,将10通过槽函数slotWork传递给run
    emit signalMain(10);

    thread->start();


}

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

void MainWindow::slotMain(int result)
{
    this->result = result;

    qDebug()<< "result="<<this->result;
}

五、Lambda 表达式

  • 格式:
    在这里插入图片描述
  1. 捕获列表:捕获一定范围内的变量
  • [] - 不捕捉任何变量
  • [&] - 捕获外部作用域中所有变量,并作为引用在函数体内使用 (按引用捕获)
  • [=] - 捕获外部作用域中所有变量,并作为副本在函数体内使用 (按值捕获) 拷贝的副本在匿名函数体内部是只读的
  • [=, &foo] - 按值捕获外部作用域中所有变量,并按照引用捕获外部变量 foo
  • [bar] - 按值捕获 bar 变量,同时不捕获其他变量
  • [&bar] - 按引用捕获 bar 变量,同时不捕获其他变量
  • [this] - 捕获当前类中的 this 指针
  • 让 lambda 表达式拥有和当前类成员函数同样的访问权限
  • 如果已经使用了 & 或者 =, 默认添加此选项
  1. 参数列表:和普通函数的参数列表一样
  2. opt 选项 –> 可以省略
  • mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)
  • exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw ();
  1. 返回值类型:
    标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略
  2. 函数体:
    函数的实现,这部分不能省略,但函数体可以为空。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QTextEdit>
#include <QDebug>
#include <QTimeEdit>


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

    //创建一个按钮
    QPushButton * btn = new QPushButton("get_name",this);
    btn->move(10,40);
    //一个文本输入框
    QTextEdit *textName = new QTextEdit("getName",this);
    textName->move(10,100);


    //在mainwindow.ui文件创建一个时间编辑器。
    QTimeEdit *timeEdit = new QTimeEdit(this);
    timeEdit->move(10,200);

    //创建一个设置时间的按钮
    QPushButton *updateTime = new QPushButton("设置时间",this);
    updateTime->move(150,200);


    //为按钮添加一个点击(鼠标点击一次就是信号)事件(点击鼠标后触发的事件就是槽),下面的是Lambda表达式
    connect(btn,&QPushButton::clicked,textName,[=](){
        textName->setText("lihua");
    });

    //为时间编辑器创建一个事件

    connect(updateTime,&QPushButton::clicked,[=](){
        //设置为当前时间
        timeEdit->setTime(QTime::currentTime());
    });


}

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

六、类型转换

QObject *obj = new MyWidget;
QWidget *widget = qobject_cast<QWidget *>(obj);

七、参考

qt入门教程

  • 7
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值