QT-数据类型&容器类&窗口控件&模态框

1. Qt 数据类型

1.1 数字类型

  • 整型: qint8、qint16、qint32、qint64

  • 无符号整型: quint8、quint16、quint32、quint64

  • qintptr: 指针类型 根据系统类型不同而不同,32位系统为qint32、64位系统为qint64 (Linux)

  • 浮点型 qreal;

cpp 复制代码
using quint16 = unsigned short;
using uint32 = unsigned int;

// 有符号,8位长度
qint8 num1 = 127; // -128-127
qint16 num2 = 32767;

// 无符号,8位长度
quint8 num3 = 255; // 0-255
quint16 num4 = 65535;

qintptr num5 = 2147483647;

// 浮点型,6位数字
qreal num6 = 3.141592653871;

1.2 位置和尺寸

  • QPoint: QPoint类封装了我们常用到的坐标点 (x, y);

  • QLine: QLine是一个直线类, 封装了两个坐标点 (两点确定一条直线);

  • QSize: QSize类用来形容长度和宽度;

  • QRect: QRect类来描述一个矩形;

cpp 复制代码
QPoint p(50, 100);
qDebug() << QString("x=%1, y=%2").arg(p.rx()).arg(p.ry());

QPoint p1(100, 50);

QLine l(p, p1);
qDebug() << l;

QSize s(200, 300);
qDebug() << s.width() << "---" << s.height();

QRect r(10, 10, 200, 300);
qDebug() << QString("x:%1,y:%2,width:%3,height:%4")
.arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height());

1.3 字符串类型

在 Qt 中使用 QString:高级类型 或 QByteArray:更偏底层,某些情况下,是可以通用的,但是在更偏底层的操作中基本都用QByteArray;例如文件读写 和 网络数据传输。

1.使用 QString 声明字符串

cpp 复制代码
QString s1 = "Hello";
QString s2 = "你好";

qDebug() << s1 << s2;

2.常用方法

cpp 复制代码
// 获取字符串长度
s.size();
s.length();
s.count();

// 大小写转换
s.toUpper();    // 转为大写字母
s.toLower();    // 转为小写字母

// 字符串拼接
s.append(" World");    // 向字符串最后追加字符串
s.prepend("~~~");      // 向字符串前面添加字符串
s.insert(2, "abc");    // 在索引2之前插入字符串 abc

// 处理空格
s.trimmed()      // 去掉字符串左右的空格
s.simplified()   // 去掉字符串左右的空格,字符串中间的多个空格合并为一个空格
  
// 索引相关
s.indexOf('o');        // 指定字符第一次出现的索引
s.lastIndexOf('o');    // 指定字符最后一次出现的索引
s.at(1);               // 查询索引为 1 的字符,并返回

// 判断字符串为空
s.isEmpty();     // 未赋值 和 赋值为空字符串是都是 true
s.isNull();      // 未赋值为 true, 赋值为空是 false

s.contains("e")      // 判断字符串 s 中是否包含 'e'
s.startsWith("H")    // 判断字符串 s 是否以 'H' 开头
s.endsWith("d")      // 判断字符串 s 是否以 'd' 结尾
  

// 字符串截取
// 参数1: 指定截取的起始点
// 参数2: 指定截取的长度。 可选参数,如果不写,截取到字符串的末尾
s.mid(2);            // 从索引2开始截取到字符串最后
s.mid(3, 5);         // 从索引3开始截取5个字符长度
  

// 字符串替换
s.replace('o', "abc");    // 将字符串中的 o 全部替换为 abc
s.section('/', 2, 3);     // 使用 / 将字符串拆分,再取出索引2、3部分,再拼接成一个字符串


// 格式化字符串   %n  占位符
QString("x=%1,y=%2,z=%3").arg(30).arg(40).arg(50);

示例:

cpp 复制代码
QString str1;
QString srt2 = "";
qDebug() << str1.isNull() << str1.isEmpty();
qDebug() << str2.isNull() << str2.isEmpty();

//section(参数1,参数2,参数3)
//使用参数1对字符串进行拆分 返回参数2-参数3之间的数
qDebug() << s.section("/", 2, 3);      // local/bin 

3.使用 QByteArray 声明字符串

cpp 复制代码
QByteArray str = "Hello World";

​qDebug() << str;
qDebug() << str.toLower();
qDebug() << str.mid(1, 3);

4.QString VS QByteArray

QString 相较 QByteArray 更高级更抽象,QByteArray 则更底层更具体。QString基本单位是一个个的Unicode字符,提供了对字符串操作的方法, QByteArray 的基本单位是一个个的字节,提供了对字节流操作的方法。

QByteArray类便于对数据进行存储和传输,在这样的场景时使用QByteArray类比较合适。而对于其他场景,则使用QString比较合适。因为QString存储的是Unicode字符,使得在应用程序中更容易存储非ASCII和非Latin-1字符,而且QString全部使用的是Qt的API。

  • QByteArray 转 QString : 使用 QString 包裹 QByteArray 类型数据

  • QString 转 QByteArray : 调用 toUtf8() 方法

  • QByteArray 类型调用 data 方法能去掉双引号

cpp 复制代码
QByteArray s3 = "Hello World";
QByteArray s4 = "你好啊";
QString    s5 = "你好!!!";

qDebug() << s3 << s4 << s5;
// QByteArray 转 QString
qDebug() << QString(s4);
// QString 转 QByteArray
qDebug() << s5.toUtf8().data();

// QByteArray 类型调用 data 方法能够去掉双引号
qDebug() << s4.data();
qDebug() << s5.toUtf8().data();

1.4 日期和时间

QDate : 日期 年-月-日

QTime: 时间 时:分:秒

QDateTime : 年-月-日 时:分:秒

cpp 复制代码
// 实例化日期
QDate d(2023,10,20);
qDebug() << d.toString() << d.toString("yyyy/MM/dd");
qDebug() << QString("%1-%2-%3").arg(d.year()).arg(d.month()).arg(d.day());

// 实例化时间
QTime t(10, 12, 40);
qDebug() << t.toString() << t.toString("hh:mm:ss");
qDebug() << QString("%1:%2:%3").arg(t.hour()).arg(t.minute()).arg(t.second());

// 实例化日期时间
// QDateTime::currentDateTime : 获取当前时间
QDateTime dt = QDateTime::currentDateTime();
qDebug() << dt.toString();
qDebug() << dt.toString("yyyy-MM-dd hh:mm:ss");
qDebug() << dt.date() << dt.date().year();
qDebug() << dt.time() << dt.time().hour();

// QDateTime::currentDateTimeUtc : 获取当前时间(GMT时间)
QDateTime dt1 = QDateTime::currentDateTimeUtc();
qDebug() << dt1.toString();
qDebug() << dt1.toString("yyyy-MM-dd hh:mm:ss");
qDebug() << dt1.date() << dt1.date().year();
qDebug() << dt1.time() << dt1.time().hour();

QDateTime dt2(QDate(2023,12,12), QTime(20,10,50));
qDebug() << dt2.toString("yyyy-MM-dd hh:mm:ss");

1.5 QVariant

  • QVariant 可以存储各种数据类型(万能类型)

  • 某些情况下,不知道具体的数据类型时,可以使用 QVariant

  • QVariant 实例化的变量,可以保存任何类型的数据

cpp 复制代码
QVariant v;
v = 100;
qDebug() << v << v.toInt();

v = 3.1415f;
qDebug() << v << v.toFloat();

v = "Hello World";
qDebug() << v << v.toString();

v = QDate(2023, 12, 12);
qDebug() << v << v.toDate() << v.toString();

2. 容器类

  • Qt 库提供了一组通用的容器类,这些容器类可以用来存储指定类型的数据。例如,如果需要一个QString类型的可变大小的数组,那么可以使用 QList<QString>。与STL(Standard Template Library,C++的标准模板库)中的容器类相比,Qt中的这些容器类更轻量,更安全,更容易使用。

  • Qt 提供的顺序容器有 QVector、QList、QStack(后进先出)和 QQueue(先进先出)等。由于这些容器中的数据都是一个接一个线性存储的,所以称为顺序容器。

  • Qt 提供的关联容器有 QMap、QMultiMap、QSet等。由于这些容器存储的是<键,值>对,比如QMap<Key, Value>,所以称为关联容器。其中"Multi"容器用来支持一个键多个值的情况。

2.1 QVector

  • QVector 类是顺序容器,它将自己的每一个对象存储在连续的内存中,可以使用下标(索引号)来快速访问

  • 可以在任意位置插入和删除元素,但在中间位置进行插入和删除操作时的性能较差。

  • 适用于需要频繁随机访问元素的场景。

示例1: QVector 创建和遍历

cpp 复制代码
// 实例化一个存储 int 类型数据的 QVector, 内部有4个单元, 保存4个数据
QVector<int> intVec = {66, 10, 100, 88};

qDebug() << intVec[0];
qDebug() << intVec[1];
qDebug() << intVec[2];
qDebug() << intVec[3];

遍历方法一(使用循环)

  • size()、 count() : 可以计算 QVector 的长度
cpp 复制代码
for(int i = 0; i < intVec.size(); i++)
{
  qDebug() << intVec[i];
}

遍历方法二 (使用迭代器)

  • begin() :返回一个STL类型的迭代器指针指向 vector 的第一个元素

  • end() :  返回一个STL类型的迭代器指针指向 vector 的最后一个元素后面的元素

cpp 复制代码
// 设置迭代器
QVector<int>::iterator iter1;

for (iter1 = intVec.begin(); iter1 < intVec.end(); iter1++)
{
  qDebug() << *iter1;
}

示例2: 常用方法

  • 向尾部插入新数据:

    • append(const T &value)

    • push_back(const T &value)

  • 向头部插入新数据:

    • prepend(const T &value)

    • push_front(const T &value)

  • 插入任意位置:

    • insert(int i, const T &value)
  • 删除数据:

    • remove(int i , int len) 删除指定位置数据

    • pop_back() 删除最后一个单元

    • pop_front() 删除第一个单元

    • clear() 清空所有单元

  • 单元替换:替换指定单元的值

    • replace(int i, const T &value)
cpp 复制代码
QVector<QString> strVec;
// 添加
strVec.append("王者荣耀");
strVec.push_back("LOL");
strVec.prepend("DNF");
strVec.insert(1, "CF");
// DNF CF 王者荣耀 LOL

// 替换
strVec.replace(1, "穿越火线");
  
// 删除
strVec.pop_back();
strVec.pop_front();
strVec.remove(1);
strVec.clear();

示例3: 常用函数

  • 判断是否为空

    • isEmpty()
  • 索引操作

    • indexOf、lastIndexOf
  • 弹出单元

    • front() : 获取第一个单元

    • back(): 获取最后一个单元

cpp 复制代码
QVector<QString> strVec = {"王者荣耀", "LOL", "DNF", "王者荣耀", "原神"};

// 计算长度
qDebug() << "strVec的长度为:" << strVec.count();
qDebug() << "strVec的长度为:" << strVec.capacity();

qDebug() << strVec.indexOf("王者荣耀");
qDebug() << strVec.lastIndexOf("王者荣耀");
qDebug() << strVec.back();
qDebug() << strVec.front();

qDebug() << strVec.empty();   // false

示例3: 应用复杂类型

cpp 复制代码
struct UserInfo
{
    qint16 id;
    QString username;
    QString password;
    bool isMarry;
};

QVector<UserInfo> userList =
{
  {1001, "admin", "123123", true},
  {1002, "root", "123456", false},
  {1003, "hhb", "123abc", false}
};

for(int i = 0; i < userList.size(); i++)
{
    qDebug() << QString("%1-%2-%3-%4").arg(userList[i].id).arg(userList[i].username)
      .arg(userList[i].password).arg(userList[i].isMarry ? "已婚" : "未婚");
}

2.2 QList

  • 链表是一种在内存中非连续的存储结构,元素的逻辑顺序是通过链表中的指针链接次序实现的。每一个元素都包括两个值:自身数据 + 下一个元素的地址(指针)。插入元素比较快。

示例1:

cpp 复制代码
QList<int> intList = {89, 123, 78, 63};

qDebug() << intList[0];
qDebug() << intList[1];
qDebug() << intList[2];
qDebug() << intList[3];

// 通过长度遍历
for(int i = 0; i < intList.size(); i++)
{
  qDebug() << intList[i];
}

// 使用迭代器遍历
QList<int>::iterator iter;
for (iter = intList.begin(); iter < intList.end(); iter++)
{
  qDebug() << *iter;
}

示例2:

cpp 复制代码
QList<QString> strList;
strList.append("aaa");
strList.push_front("bbb");
strList.insert(1, "ccc");

QList<QString>::iterator iter;
for (iter = strList.begin(); iter < strList.end(); iter++)
{
  qDebug() << *iter;
}

示例3:

cpp 复制代码
QList<UserInfo> userList =
{
  {1001, "admin", "123123", true},
  {1002, "root", "123456", false},
  {1003, "hhb", "123abc", false}
};

QList<UserInfo>::Iterator iter;
for (iter = userList.begin(); iter < userList.end(); iter++)
{
  qDebug() << QString("%1-%2-%3-%4").arg(iter->id).arg(iter->username)
    .arg(iter->password).arg(iter->isMarry ? "已婚" : "未婚");
}

for(int i = 0; i < userList.count(); i++)
{
  qDebug() << QString("%1-%2-%3-%4").arg(userList[i].id).arg(userList[i].username)
    .arg(userList[i].password).arg(userList[i].isMarry ? "已婚" : "未婚");
}

QVector VS QList

  • QVector 是一个基于数组的动态数组类,支持高效的随机访问。

  • 可以在任意位置插入和删除元素,但在中间位置进行插入和删除操作时的性能较差。

  • 适用于需要频繁随机访问元素的场景。

  • QList 是一个双向链表类,支持高效的插入和删除操作。

  • 可以在任意位置插入和删除元素,而不会导致整个链表的重新分配和复制。

  • 适用于需要频繁插入和删除元素的场景。

2.3 QStringList

QStringList继承自QList<QString>, 使用方式与QList一样。但是,只能操作字符串数据

QStringList <===> QList<QString>

cpp 复制代码
QStringList sl1 = {"aa", "bb", "cc"};
qDebug() << sl1[0];
qDebug() << sl1[1];
qDebug() << sl1[2];


QStringList sl2;
sl2 << "C++" << "Java" << "C#";
sl2.append("PHP");
sl2.prepend("前端");

for (int i = 0; i < sl2.size(); i++) {
  qDebug() << sl2[i];
}


// 字符串分割
QStringList sl = s.split(",");   // 使用 , 将字符串拆分成一个list

// 字符串拼接
QStringList sl = {"aa", "bb", "cc"};
qDebug() << sl.join("-");    // aa-bb-cc

QStringList sl = {"盗墓笔记", "鬼吹灯", "茅山后裔", "上古神迹", "宝莲灯"};

qDebug() << sl.contains("鬼吹灯");        // true
QStringList result = sl.filter("灯");    // {"鬼吹灯", "宝莲灯"}

qDebug() << sl.join("-");                // 盗墓笔记-鬼吹灯-茅山后裔-上古神迹-宝莲灯

QString str = "盗墓笔记-鬼吹灯-茅山后裔";
QStringList sl = str.split("-");         // {"盗墓笔记","鬼吹灯","茅山后裔"}

2.4 QMap

Map 类是 Qt 的关联容器,它存储(键,值)对并提供了与键相关的值的快速查找。

cpp 复制代码
// 创建 Map 类型, QString 是 key 的数据类型, int 是 value 的数据类型
QMap<QString, int> m1;
m1["one"] = 111;
m1["two"] = 222;      // {{"one", 111}, {"tow", 222}}

qDebug() << m1["one"];
qDebug() << m1["two"];

QMap<QString, QString>  m2;
m2["id"] = "10001";
m2["name"] = "zss";
// 使用方法添加 key-value
m2.insert("isMarry", "未婚");

qDebug() << m2["id"];
qDebug() << m2["name"];
qDebug() << m2["isMarry"];

遍历:

cpp 复制代码
// 创建迭代器
QMapIterator<QString, QString> iter(m2);

// hasNext 方法用来判断是否还有下一个单元
while (iter.hasNext()) {
  // 调整到下一个单元
	iter.next();
  // key 方法用来得到当前的 key数据
  // value 方法用来的到当前的 value数据
	qDebug() << "key:" << iter.key() << " value:" << iter.value();
}

2.5 QHash

QHash 也是一个关联容器,功能与 QMap 几乎一样。

cpp 复制代码
QHash<QString, QVariant> h;
h["id"] = 10001;
h["brand"] = "奔驰";
h["model"] = "GLC 300L";
h["price"] = 43.98f;

qDebug() << h["id"] << h["id"].toInt();
qDebug() << h["brand"] << h["brand"].toString();
qDebug() << h["model"] << h["model"].toString();
qDebug() << h["price"] << h["price"].toFloat();


QHash<QString, QVariant>::const_iterator iter;
for (iter = h.constBegin(); iter != h.constEnd(); iter++)
{
  qDebug() << *iter;
}

for (auto val : carHash)
{
  qDebug() << val;
}

// key() : 通过值的到key
qDebug() << carHash.key("比亚迪");
// value() : 通过key得到值
qDebug() << carHash.value("id");

qDebug() << carHash.keys();      // 获取所有的 key
qDebug() << carHash.values();    // 获取所有的 value

QMap VS QHash

  • QMap和QHash的接口相同,可直接替换使用

  • QHash的查找速度明显快于QMap

  • QHash占用的存储空间明显多于QMap

  • QHash以任意的方式存储元素

  • QMap以Key顺序存储元素

3. 窗口控件

  • Qt 中的窗口有三种: QWidget、 QMainWindow、 QDialog

    • QWidget 是空窗口

    • QMainWindow 是带有菜单栏、工具栏、状态栏等扩展功能的窗口

    • QDialog 是各种对话框的基类

    • QMainWindow 和 QDialog 继承于 QWidget

  • QObject 和 OPaintDevice

    • QObject 是所有Qt对象的基类

    • QPaintDevice 是所有可以绘制的对象的基类

4. QDiaLog

Dialog 用来创建弹出框,弹出框分为两种: 模态框 和 非模态框

4.1 模态框

  • 模态框是一种弹出框, 当模态框弹出时,其他窗口无法再操作

  • QDialog 类用来创建弹出框

  • exec 方法能够显示模态框

  • 模态框特点: 阻塞, 关闭时系统自动回收资源

cpp 复制代码
connect(ui->btn1, &QPushButton::clicked, [=](){
  // 创建弹出框
  QDialog dia(this);
  // 设置弹出框大小和标题栏
  dia.resize(300, 300);
  dia.setWindowIcon(QIcon(":/images/Jinx.jpeg"));
  dia.setWindowTitle("模态框");

  // 为弹出框中添加部件
  QLabel *l = new QLabel("哈哈哈", &dia);
  l->move(50, 50);

  QPushButton *btn = new QPushButton("关闭", &dia);
  btn->setFixedSize(60, 30);
  btn->move(240, 0);

  // 为弹出框中的按钮添加信号和槽
  connect(btn, &QPushButton::clicked, &dia, &QWidget::close);
  // 以模态框形式弹出, 有阻塞效果
  dia.exec();

  // 当关闭模态框时才会执行输出
  qDebug() << "弹出模态框";
});

4.2 非模态框

  • 非模态框也是一种弹出框, 当非模态框弹出时,其他窗口可以继续操作

  • QDialog 类用来创建弹出框

  • show 方法能够显示非模态框

  • 非模态框特点: 不阻塞, 关闭时需要自己回收资源

  • 注意事项:

    • 非模态框需要使用 dia->setAttribute(Qt::WA_DeleteOnClose) 来销毁对象

    • setModel(true/false) 也能设置 模态框/非模态框

cpp 复制代码
connect(ui->btn2, &QPushButton::clicked, [=](){
	if (dia != nullptr)
  {
    return ;
  }
  
  dia = new QDialog(this);
  dia->resize(200, 300);
  // 关闭时,自动销毁该模态框
  dia->setAttribute(Qt::WA_DeleteOnClose);

  QLabel *l = new QLabel("非模态框测试", dia);
  l->move(100, 0);

  QPushButton *btn = new QPushButton("close", dia);
  connect(btn, &QPushButton::clicked, [=](){
    dia->close();
    dia = nullptr;
  });

  // true 模态框 | false 非模态框
  // dia->setModel(true);
  // 以非模态框形式显示
  dia->show();
  qDebug() << "弹出非模态框";
});

5.练习

cpp 复制代码
//封装一个函数,传入一个文件路径,将路径进行拆分,得到以下数据:
//1.  文件所在文件夹的绝对路径       (d:/aaa/bbb/ccc)
//2.  文件名                                   (a.txt)
//3.  文件后缀                                  (.txt)
//4.  纯文件名                                (a)

//path = "d:/aaa/bbb/ccc/a.txt";
//void convert (QString path); 


//可选    (账号就是 @ 前面的字符串:  admin@qq.com --> admin)
//任务2:  邮箱的长度在 10到30位之间
//任务3:  密码长度在 6到18位之间
//任务4:  密码中必须有 &#$. 其中之一
//任务5:  账号为 admin,密码为 123.123
 //       账号为 root,密码为 123456$
 //       账号为 zss, 密码为 1232#13  则提示登录成功
 //       否则,提示账号或者密码错

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QPushButton>
#include <QTime>  // 时分秒
#include <QDate>  // 年月日
#include <QDateTime>  //年月日 + 时分秒


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

    QString str = "d:/aaa/bbb/ccc/a.txt";
    qDebug() << str.section("/",0,3);
    qDebug() << str.section("/",4);
    qDebug() << str.section("/",4).mid(1,4);
    qDebug() << str.section("/",4).mid(0,1);

    connect(ui->pushButton,&QPushButton::clicked,[this](){
    QString tmp1 = ui->linezhanghao->text().trimmed();
    //tmp1 = tmp1.mid(0,tmp1.size()-1);
    if(tmp1.size() < 10 || tmp1.size() > 30)
    {
        qDebug() << "请输入邮箱的长度在 10到30位之间";
        return;
    }
    QString tmp2 = ui->linemima->text().trimmed();
    //tmp2 = tmp2.mid(0,tmp2.size()-1);
    if (tmp2.size() < 6 || tmp2.size() > 18 && tmp2.contains("&") == true
            && tmp2.contains("#") == true && tmp2.contains("$") == true && tmp2.contains(".") == true)
    {
        qDebug() << "请输入密码长度在 6到18位之间";
         return;
    }

    int index = tmp1.indexOf("@");
    if(tmp1.mid(0,index) == "admin" && tmp2 == "123.123")
    {
        qDebug()<< "登录成功";

    }
    else if (tmp1.mid(0,index) == "root" && tmp2 == "123456$") {
        qDebug()<< "登录成功";
    }
    else if (tmp1.mid(0,index) == " zss" && tmp2 == "1232#13") {
         qDebug()<< "登录成功";
    }
    else {
        qDebug() << "账号或者密码错";
    }


//    if(tmp2.contains("&") == true)
//    {
//        qDebug() << "密码&正确";
//    }
//    else {
//         qDebug() << "请输入&在密码中";
//    }

    });
}

Widget::~Widget()
{
    delete ui;
}
相关推荐
legend_jz11 分钟前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
tangliang_cn32 分钟前
java入门 自定义springboot starter
java·开发语言·spring boot
程序猿阿伟33 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
新知图书44 分钟前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
威威猫的栗子1 小时前
Python Turtle召唤童年:喜羊羊与灰太狼之懒羊羊绘画
开发语言·python
力透键背1 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript
bluefox19791 小时前
使用 Oracle.DataAccess.Client 驱动 和 OleDB 调用Oracle 函数的区别
开发语言·c#
ö Constancy1 小时前
c++ 笔记
开发语言·c++
墨染风华不染尘1 小时前
python之开发笔记
开发语言·笔记·python
徐霞客3201 小时前
Qt入门1——认识Qt的几个常用头文件和常用函数
开发语言·c++·笔记·qt