C++ QT 简介

介绍

安装社区版本,多种下载方式

https://www.qt.io/

https://download.qt.io/

常用的快捷键

使用Clion 开发QT

https://zhuanlan.zhihu.com/p/461896034

信号槽

  • 信号槽是 Qt 框架引以为豪的机制之一。熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力。
  • 所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。(这里提一句,Qt 的信号槽使用了额外的处理来实现,并不是 GoF 经典的观察者模式的实现方式。)

connect(sender,SIGNAL(signal),receiver,SLOT(slot),Qt::DirectConnection);

sender :发送信号指针(对象)

SIGNAL: 信号(函数)
    signals:
    //发射信号,不需要实现
    void ageChanged(unsigned value);
    
receiver: 接收指针(对象)

SLOT(slot): 槽(执行函数)

QT::DirectConnection :链接方式,默认:QT::DirectConnection
    Qt::DirectConnection参数  参数含义
    Qt::AutoConnection  默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。
    Qt::DirectConnection  槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。
    Qt::QueuedConnection  槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
    Qt::BlockingQueuedConnection  槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
    Qt::UniqueConnection  这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。
  

5种信号槽实现方式

5种信号槽实现方式

元对象系统

QObject *obj = new QPushButton;

obj->metaObject()->className();  //返回类名称:"QPushButton"


QTimer *timer = new QTimer; // QTimer 是一个QObject的子类
timer->inherits("QTimer"); // timer是不是一个QTimer类或者QTimer指针, true
timer->inherits("QObject");// true
timer->inherits("QAbstrctButton"); //false

功能实例

属性系统

定义属性


Q_PROPERTY(type name READ name WRITE setname NOTIFY nameChanged)
Q_PROPERTY(bool enabled,READ isEnabled WRITE setenabled NOTIFY enabledChanged)
type 类型 C++的基础类型
READ 读取属性的函数
WRITE 设置属性的函数
NOTIFY 通知函数(属性改变了会调用这个函数)

动态设置属性

bool setProperty(const char *name, const QVariant &value);
QObject obj;
obj.setProperty("flat",true);

类的附加信息

Q_CLASSINFO("AUTHOR","WANGLAOJU")
Q_CLASSINFO("AUTHOR","WANGLAOJU")
Q_CLASSINFO("AUTHOR","WANGLAOJU")
Q_CLASSINFO("AUTHOR","WANGLAOJU")

//获取属性
this->metaObject()->classInfo(2).name();
this->metaObject()->classInfo(2).value();


QtGolbal 全局定义

forever{
  //无限循环
}

Qt容器类

    QList<QString> asList;
    asList.append("Moday");
    asList.append("TuesDay");
    asList.append("Wdnesday");
    QString str = asList[0]; // "Moday"
    qDebug() << str;
    QList<QString> list;
    list << "noe" << "two" << "three";
    QString str1 = list[1]; // "two"
    QString str0 = list.at(0); // one
    qDebug()<< "str1 = " << str1 << ",str0 = " << str0;
    
    //QLinkedList 和 QVector 类似QList函数接口
    //QVector 访问性能更高,QLinkedList添加删除效率更高
    
      QStack<int> stack ;
    stack.push(1231);
    stack.push(1);
    stack.push_front(23);

    qDebug()<< stack.pop() << "->" << stack.pop() << "->" << stack.pop();

    QQueue<int> queue;
    queue.enqueue(10);
    queue.enqueue(20);
    queue.enqueue(30);

    while(!queue.isEmpty()){
        qDebug()<<queue.dequeue();
    }

    QSet<QString> set;
    set << "dgo" << "cat" << "tiger";
    if(set.contains("cat")){
        qDebug()<< "the set hash cat ";
    }


    QMap<QString,int> map; // key不可重复
    map["1"] = 1;
    map["2"] = 2;
    map["3"] = 3;

    qDebug()<< map["1"] <<map.value("2") << map.value("4",40);



    QMultiMap<QString,int> mutableMap; // key value 可以重复

    mutableMap.insert("1",2);
    mutableMap.insert("1",20);
    mutableMap.insert("1",230);
    mutableMap.insert("1",22300);
    qDebug() << "mutableMap.value('1') == " << mutableMap.value("1");
    foreach (int i, mutableMap) {
        qDebug() << "mutableMap=>" << i;
    }



容器迭代

容器 只读遍历器 读写遍历器
QList,QQueue QListIterator QMutableListIterator
QLinkedList QLinkedListIterator QMutableLinkedListIterator
QVector,QStack QVectorIterator QMutableVectorIterator
QSet QSetIterator QMutableSetIterator
QMap<key, t="">,QMultiMap<key, t=""> QMapIterator QMutableMapIterator
QHash<key, t="">,QMultiHash<key, t=""> QHashIterator QMutableHashIterator
容器 只读遍历器 读写遍历器
QList,QQueue QList::const_iterator QList::iterator
QLinkedList QLinkedList::const_iterator QLinkedList::iterator
QVector,QStack QVector::const_iterator QVector::iterator
QSet QSet::const_iterator QSet::iterator
QMap<key, t="">,QMultiMap<key, t=""> QMap<key, t="">::const_iterator QMap<key, t="">::iterator
QHash<key, t="">,QMultiHash<key, t=""> QHash<key, t="">::const_iterator QHash<key, t="">::iterator

Qt核心模块

名称 功能
Qt Core 非图形相关的基础类。
Qt GUI 图形界面相关的基础类。
Qt Multimedia 用于支持音视频、摄像头功能的类。
Qt Multimedia Widgets 用于支持多媒体的图形类。
Qt Network 用于简化网络编程的类。
Qt QML QML and JavaScript 相关的类。
Qt Quick 用于构建高动态和易交互的用户界面的声明式框架。
Qt Quick Controls 提供轻量级的 QML 类型,用于为桌面、嵌入式和移动设备创建高性能的用户界面。
Qt Quick Dialogs 用于创建对话框的 QML types。
Qt Quick Layouts 用于布局的 QML types
Qt Quick Test 用于对 QML 应用的进行单元测试
Qt SQL 用于 SQL 相关的操作
Qt Test 用于对 Qt 应用和库进行单元测试
Qt Widgets 提供了一组 UI 元素来创建经典用户界面

Qt附加模块

模块  描述
Active Qt  用于开发使用 ActiveX 和 COM 的 Windows 应用程序
Qt 3D  支持 2D 和 3D 渲染,提供用于开发近实时仿真系统的功能
Qt Android Extras  提供 Android 平台相关的 API
Qt Bluetooth  提供访问蓝牙硬件的功能
Qt Concurrent  提供一些类,无需使用底层的线程控制就可以编写多线程程序
Qt D-Bus  使进程间通过 D-Bus 协议通信的一些类
Qt Gamepad  使 Qt 应用程序支持游戏手柄硬件的使用
Qt Image Formats   支持附加图片格式的插件,包括 TIFF、MNG、TGA、WBMP
Qt Mac Extras  提供 macOS 平台相关的 API
Qt NFC  提供访问 NFC (近场通信)硬件的功能
Qt Positioning  提供一些类,用于通过 GPS 卫星、WiFi 等定位
Qt Print Support  提供一些用于打印控制的类
Qt Purchasing  提供一些类,在 Qt 应用程序内实现应用内购买的功能
Qt Sensors  提供访问传感器硬件的功能,以识别运动和手势
Qt Serial Bus  访问串行工业总线的功能,目前只支持 CAN 和 Modbus 协议
Qt SVG  提供显示 SVG 图片文件的类
Qt WebChannd  用于实现服务器端(QML 或 C++ 应用程序)与客户端(HTML/JavaScript 或 QML 应用程序)之间的 P2P 通信
Qt WebEngine  提供类和函数,实现在应用程序中嵌入网页内容
Qt WebSocket  提供兼容于 RFC 6455 的 WebSocket 通信,是实现客户端程序与远端主机进行双向通信的基于 Web 的协议
Qt Windows Extras  提供 Windows 平台相关的 API
Qt XML  该模块不再维护了,应使用 QtCore 中的 QXmlStreamReader 和 QXmlStream Writer Qt XML Patterns 提供对 XPath、XQuery、XSLT 和 XML 等的支持
Qt Charts   用于数据显示的二维图表组件
Qt Data Visualization  用于 3D 数据可视化显示的界面组件
Qt Virtual Keyboard  实现不同输入法的虚拟键盘框架

增值模块

除了随 Qt 5 发布的上述这些模块,还有一些模块(见表 3)是单独发布的,这些模块只在商业版许可的 Qt 里才有。

3 Qt的增值模块
特性  描述
Qt for Device Creation  高效、易用、全集成的嵌入式设备应用程序开发工具,包括很多其他增值特性
Qt Quick Compiler  编译.qml 源文件生成二进制应用程序的编译器,提高载入时间和代码的安全性

技术预览模块

技术预览模块就是一些还处于开发和测试阶段的模块,一般技术预览模块经过几个版本的发布后会变成正式的模块。表 4 是 Qt 5.9 中的技术预览模块。

模块  描述
Qt Network Authorization  基于 OAuth 协议,为应用程序提供网络账号验证的功能
Qt Speech  提供文字转语音(text-to-speech)功能支持
Qt Remote Objects  进程间或设备间通信,共享 QObject 的 API

Qt 工具


Qt 工具(见表 5)在所有支持的平台上都可以使用,用于帮助应用程序的开发和设计。

工具  描述
Qt Designer  用于扩展 Qt Designer 的类
Qt Help  在应用程序中集成在线文档的类,实现类似于 Qt Assistant 的功能
QtUI Tools  操作 Qt Designer 生成的窗体的类

QSpinBox 旋转框

二进制显示这些都是这个组件的特有的

例子:

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

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

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

void Widget::setTotal()
{
    int num = ui->doubleSpinBox1->value();
    float price = ui->doubleSpinBox2->value();
    float total = num*price;
    ui->doubleSpinBox3->setValue(total);


}

void Widget::on_pushButton_5_clicked()
{
    this->setTotal();
}
void Widget::on_doubleSpinBox1_valueChanged(double arg1)
{
    this->setTotal();
}
void Widget::setToBase(int number)
{
    ui->spinBox_4->setValue(number);
    ui->spinBox_5->setValue(number);
    ui->spinBox_6->setValue(number);
    ui->spinBox_7->setValue(number);
}
void Widget::on_pushButton_clicked()
{
    int bin = ui->spinBox_4->value();
    setToBase(bin);
}
void Widget::on_pushButton_2_clicked()
{
    int dec = ui->spinBox_5->value();
     setToBase(dec);

}

void Widget::on_pushButton_3_clicked()
{
    int otc = ui->spinBox_6->value();
     setToBase(otc);
}

void Widget::on_pushButton_4_clicked()
{
    int hex = ui->spinBox_7->value();
     setToBase(hex);
}
void Widget::on_spinBox_4_valueChanged(int arg1)
{
    int bin = ui->spinBox_4->value();
    setToBase(bin);
}


QSlider 其他数字输入和显示组件

QTime.....日期和其他控件

例子:

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

#include <QDebug>

#include <QTimer>


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

    //定时器,没时隔1s 调用SLOT函数
    this->fTimer = new QTimer(this);
    //设置间隔
    this->fTimer->setInterval(1000);
    this->fTimer->stop();
    connect(fTimer,SIGNAL(timeout()),this,SLOT(on_timer_timeout()));

}

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


void Widget::on_readCourrentTime_btn_clicked()
{
    //获取当前时间
    QDateTime curDateTime = QDateTime::currentDateTime();

    //时间
    ui->timeEdit->setTime(curDateTime.time());

    //日期
    ui->dateEdit->setDate(curDateTime.date());

    //时间日期
    ui->dateTimeEdit->setDateTime(curDateTime);

    //时间转字符
    ui->time_lineEdit->setText(curDateTime.toString("HH:mm:ss"));
    ui->date_lineEdit->setText(curDateTime.toString("yyyy-MM-dd"));
    ui->dateTime_lineEdit->setText(curDateTime.toString("yyyy-MM-dd HH:mm:ss"));
}



void Widget::on_setTime_btn_clicked()
{
    QString str= ui->time_lineEdit->text();
    //字符转时间
    QTime time = QTime::fromString(str,"HH:mm:ss");
    ui->timeEdit->setTime(time);

}


void Widget::on_setDate_btn_clicked()
{
    QString str = ui->date_lineEdit->text();
    QDate date = QDate::fromString(str,"yyyy-MM-dd");
    ui->dateEdit->setDate(date);
}


void Widget::on_setDateTime_btn_clicked()
{
    QString str = ui->dateTime_lineEdit->text();
    QDateTime dateTime = QDateTime::fromString(str,"yyyy-MM-dd HH:mm:ss");
    ui->dateTimeEdit->setDateTime(dateTime);
}


void Widget::on_calendarWidget_selectionChanged()
{
    QDate date = ui->calendarWidget->selectedDate();
    ui->selectDate_lineEdit->setText(date.toString("yyyy-MM-dd"));
    qDebug()<< "日历选择时间:" <<date;
}



void Widget::on_timer_timeout()
{
    //获取当前时间,设置LCD
    ui->lcdNumber->display(QTime::currentTime().hour());
    ui->lcdNumber_2->display(QTime::currentTime().minute());
    ui->lcdNumber_3->display(QTime::currentTime().second());
    //设置进度条
    int value = ui->progressBar->value();
    value++;
    if(value>=100){
        value=0;
    }
    ui->progressBar->setValue(value);

}


void Widget::on_setDateRole_btn_clicked()
{
    fTimer->setInterval(ui->spinBox->value());
}


// 开始
void Widget::on_start_btn_clicked()
{
    this->fTimer->start();
    ui->start_btn->setEnabled(false);
    ui->setDateRole_btn->setEnabled(false);
    ui->end_btn->setEnabled(true);

    //开始记时
    this->fTimerCounter.start();

}


void Widget::on_end_btn_clicked()
{
    this->fTimer->stop();
    ui->start_btn->setEnabled(true);
    ui->setDateRole_btn->setEnabled(true);

    //返回自上次调用start()或restart()以来经过的毫秒数。
    int tmMsecl= this->fTimerCounter.elapsed();
    int sec = tmMsecl/1000; // 获取秒数
    int mSec = tmMsecl%1000; //获取毫秒数
    ui->label_5->setText(QString::asprintf("时间流逝: %1 秒 %2 毫秒").arg(sec).arg(mSec));
}


QApplication

qApp->processEvents(); //作用是处理密集型耗时的事情。

有时候需要处理一些跟界面无关的但非常耗时的事情,这些事情跟界面在同一个线程中,由于时间太长,导致界面无法响应,处于“假死”状态。例如:在应用程序中保存文件到硬盘上,从开始保存直到文件保存完毕,程序不响应用户的任何操作,窗口也不会重新绘制,从而处于“无法响应”状态,这是一个非常糟糕的体验 。

在这种情况下,有一种方法是使用多线程,即在子线程中处理文件保存,主线程负责界面相关。

而如果不想使用多线程,最简单的办法就是在文件保存过程中频繁调用QApplication::processEvents()。该函数的作用是让程序处理那些还没有处理的事件,然后再把使用权返回给调用者。

QFile文件

QFile

打开一个文件

#include <QFile>
#include <QByteArray> 

QFile有三个open()函数重载

bool open(FILE *fh, QIODevice::OpenMode mode, QFileDevice::FileHandleFlags handleFlags = DontCloseHandle)
bool open(int fd, QIODevice::OpenMode mode, QFileDevice::FileHandleFlags handleFlags = DontCloseHandle)
virtual bool open(QIODevice::OpenMode mode) override  //常用

开始使用:

  QFile file("G:\\C++Project\\Demo\\Duplicate_file_detection\\CMakeLists.txt");

  if(file.open( QIODevice::ReadOnly)){
      QByteArray content = file.readAll();

      qDebug() <<  content.toStdString().c_str() << "\n文件读取完毕";

      file.close();
  }

QDir & QFileInfo

递归遍历文件

QStringList Duplicate::getFiles(const QString filesPath)
{
    QStringList ret;
    QDir dir(filesPath); // 查看G:/xx/xxxx 下的文件

    //QStringList dirList = dir.entryList();//返回目录下的所有文件

    QFileInfoList infoList = dir.entryInfoList(QDir::Files | QDir::Dirs |QDir::NoDotAndDotDot);//返回文件信息,过滤文件信息: .表示当前目录,..表示上一级目录

    //for(int i =0;i< infoList.count();i++){ infoList.at(i)}
    for(auto info : infoList){
        //是不是一个目录
        if(info.isDir()){
            QString fileinfo = info.absoluteFilePath();
            //递归遍历目录结构
            QStringList files = getFiles(fileinfo);
            ret.append(files);

        }else{
            //是一个文件
            QString fileName= info.absoluteFilePath();
            ret.append(fileName);

        }

    }
    return ret;
}

QMessageBox消息弹窗:

#include <QMessageBox>

对应方法

static StandardButton information(QWidget *parent, const QString &title,const QString &text, StandardButtons buttons = Ok,StandardButton defaultButton = NoButton);
static StandardButton question(QWidget *parent, const QString &title,const QString &text, StandardButtons buttons = StandardButtons(Yes | No),StandardButton defaultButton = NoButton);
static StandardButton warning(QWidget *parent, const QString &title,const QString &text, StandardButtons buttons = Ok,StandardButton defaultButton = NoButton);
static StandardButton critical(QWidget *parent, const QString &title,const QString &text, StandardButtons buttons = Ok,StandardButton defaultButton = NoButton);

开始使用:

#include <QMessageBox>
......
//QMessageBox::information(this,"读取文件内容",str);
//QMessageBox::critical(this,"错误警告","文件读取失败");
//QMessageBox::question(this,"询问操作","确定要关闭软件吗");
QMessageBox::warning(this,"警告","文件未保存");

QCryptographicHash加密:

例子:

QCryptographicHash Demo

QListWidget和QToolButton

这个组件非常实用

组件 TooBox,常用于侧边栏,配合 tab Widget使用,就类似和web前端类似了

组件tab Widget

例子:

QListWidget和QToolButton

QTreeWidget和QDockWidget

使用案例:

QTreeWidget和QDockWidget Demo

QPixmap 图片

QPixmap类是一种可以用作绘制设备的屏幕外图像表示

QTableWidget

表格的第 1 行称为行表头,用于设置每一列的标题,第 1 列称为列表头,可以设置其标题,但一般使用缺省的标题,即为行号。行表头和列表头一般是不可编辑的。  

除了行表头和列表头之外的表格区域是内容区,内容区是规则的网格状,如同一个[二维数组](http://c.biancheng.net/c/array/),每个网格单元称为一个单元格。每个单元格有一个行号、列号,图 1 表示了行号、列号的变化规律。  

在 QTableWidget 表格中,每一个单元格是一个 QTable Widgetltem 对象,可以设置文字内容、字体、前景色、背景色、图标,也可以设置编辑和显示标记。每个单元格还可以存储一个 QVariant 数据,用于设置用户自定义数据。

例子:

TableWidgetDemo

Model/View结构

数据模型

QFileSystemModel

适配TableView TreeView ListView

如同Widnows的资源管理器一样。使用QFileSystemModel提供的接口函数,可
以创建目录、删除目录、重命名目录,可以获得文件名称、目录名称、文件大小等
参数,还可以获得文件的详细信息。

QFileSysetmModel *model = new QFileSystemMOdel;
mode->setRootPath(Qt::Dir::currentPath());

效果

![](https://secure2.wostatic.cn/static/q2KK87YNQkX8YqUzNnZpD4/image.png)


例子:

QFileSystemModelDemo

QStringListModel

QStringListModelDemo

QStandardItemModel

配合QTableView组合成Model/View , 每一行的每一项 都有自己的信息内容

例子:

QStringListModelDemo

视图组件

![](https://secure2.wostatic.cn/static/gf95axW2MFFzWcieGVLcBn/image.png)

代理

![](https://secure2.wostatic.cn/static/fJyCBV5eh8NW9UJurRrDYk/image.png)
代理是在Model和View之间的动作,
表格内的每一个单元可以能是:下拉框,单选框,多选框等等, 代理就是适配表格单元动作

例子:

代理Demo

标准对话框

  • 用户选择一个文件
  • 用户另存为文件
  • 标准消息框
  • 标准输入框

例子:

标准对话框Demo

自定义对话框

创建新文件,Dialog文件即可完成

多窗体应用

多个TabWidget

案例

多窗体应用程序

MDI应用程序

QMdiArea(Multiple Document Interface Area)提供了一个可以同时显示多个文档窗口的区域。每一个窗口都是一个 QMdiSubWindow对象

MDI 有两种模式 MdiArea:SubWindowView是传统的子窗口模式 QMdiArea:TabbedView定多页的显示模式, 设置模式使用setViewMode()函数

posted @   Amani_Bey  阅读(455)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示