【QT】-- QT基础类


前言

  • Qt是C++一个开发框架,具有跨平台特性。
  • 这篇是作者大二学习的时候做的笔记,有可能有错误,请各位批评指正。
  • 这篇记录Qt基础类型,当然更详细请看Qt文档或者AI
  • 欢迎大家点赞+收藏,作者将会持续更新。

文章目录

1. 基础类型

因为Qt是一个C++框架, 因此C++中所有的语法和数据类型在Qt中都是被支持的, 但是Qt中也定义了一些属于自己的数据类型。

Qt基本数据类型定义在#include <QtGlobal> 中,Qt基本数据类型有:

类型名称 注释 备注
qint8 signed char -126 ~ 127 有符号8位数据
qint16 signed short 16位数据类型
qint32 signed short 32位有符号数据类型
qint64 long long int 或(__int64) 64位有符号数据类型,Windows中定义为__int64
qintptr qint32 或 qint64 指针类型 根据系统类型不同而不同,32位系统为qint32、64位系统为qint64
qlonglong long long int 或(__int64) Windows中定义为__int64
qptrdiff qint32 或 qint64 根据系统类型不同而不同,32位系统为qint32、64位系统为qint64
qreal double 或 float 除非配置了-qreal float选项,否则默认为double
quint8 unsigned char 无符号8位数据类型
quint16 unsigned short 无符号16位数据类型
quint32 unsigned int 无符号32位数据类型
quint64 unsigned long long int 或 (unsigned __int64) 无符号64比特数据类型,Windows中定义为unsigned __int64
quintptr quint32 或 quint64 根据系统类型不同而不同,32位系统为quint32、64位系统为quint64
qulonglong unsigned long long int 或 (unsigned __int64) Windows中定义为__int64
uchar unsigned char 无符号字符类型
uint unsigned int 无符号整型
ulong unsigned long 无符号长整型
ushort unsigned short 无符号短整型
qsizetype size_t

💁‍♂ 提示:直接用C++的我感觉也挺好

2. log输出

在Qt中进行log输出, 一般不使用c中的printf, 也不是使用C++中的cout, Qt框架提供了专门用于日志输出的类, 头文件名为 QDebug

基本分类

  • qDebug:调试信息提示
  • qInfo :输出信息
  • qWarning :一般的警告提示,注意这个
  • qCritical :严重的错误提示,注意这个
  • qFatal :致命错误提示,会直接中断程序,结合assert

C风格输出

cpp 复制代码
qDebug("我是%s,今年%d岁了~","w",20);
qInfo("w%d",666);
qWarning("hello %s","warning");
qCritical("helo %s","critical");
qFatal("hello %s","qFatal");		//致命错误会直接中断程序

C++风格

cpp 复制代码
qDebug()<<"好帅"<<endl;
qInfo()<<"qInfo"<<endl;
qWarning()<<"qWarnning"<<endl;
qCritical()<<"qCritical"<<endl;
#qFatal()<<"qFatal"<<endl;			//致命错误不能用<<输出

格式化日志

💁‍♂ 有印象即可

默认情况下,日志格式是只输出对应的日志内容没有额外信息的。

我们可以通过修改环境变量QT_MESSAGE_PATTERN或者调用方法 qSetMessagePattern来修改日志的输出格式。

日志格式中常用的占位符号如下所示:

shell 复制代码
%{appname}     应用程序的名称(QCoreApplication::applicationName())
%{category}    日志所处的领域
%{file}        打印该日志的文件路径 
%{function}    打印日志的函数
%{line}        打印日志在文件中的行数
%{message}     日志的内容
%{pid}         打印日志的程序的PID(QCoreApplication::applicationPid())
%{threadid}    打印日志的线程ID
%{qthreadptr}  打印日志的线程指针
%{type}        日志级别("debug", "warning", "critical" or "fatal")
%{time process}日志发生时程序启动了多久
%{time boot}   日志发生时系统启动了多久
%{time [format]}以固定时间格式输出日志打印的时间,默认为QISODate格式

普通格式化

格式化日志方法如下:

cpp 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

	qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} [%{type}] %{file} [%{function}(%{line})]  %{message}");
    qInfo()<<"info";
    qDebug()<<"debug";
    qWarning()<<"warning";
    qCritical()<<"Critical";

    return a.exec();
}

输出的日志内容如下:

css 复制代码
2023-09-23 15:57:30 [info] F:/Downloads/QtFirstPro/main.cpp [qMain(43)]  info
2023-09-23 15:57:30 [debug] F:/Downloads/QtFirstPro/main.cpp [qMain(44)]  debug
2023-09-23 15:57:30 [warning] F:/Downloads/QtFirstPro/main.cpp [qMain(45)]  warning
2023-09-23 15:57:30 [critical] F:/Downloads/QtFirstPro/main.cpp [qMain(46)]  Critical

**注意:**在Release模式下,文件名、函数名、行号获取不到,需要添加编译时宏QT_MESSAGELOGCONTEXT

条件格式化(什么条件输出什么东西)

可以设置不同条件下的输出

在消息参数中还可以使用条件,给不同级别的日志指定不同的格式,语法如下:

复制代码
%{if-<debug | info | warning | critical | fatal>} ... %{endif}

比如,只想在debug级别下输出文件名、函数名以及行号,代码格式如下:

cpp 复制代码
 qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} [%{type}] %{if-debug}%{file}%{endif} %{if-} [%{function}(%{line})]  %{message}");  // if-debug模式

环境变量设置格式化

模式也可以在运行时通过设置QT_MESSAGE_PATTERN环境变量来更改;

如果调用了qSetMessagePattern()并且设置了QT_MESSAGE_PATTERN,则环境变量优先。

cpp 复制代码
qputenv("QT_MESSAGE_PATTERN", QByteArray("%{time yyyy-MM-dd hh:mm:ss} [%{type}] %{file} [%{function}(%{line})]  %{message}"));

日志输出位置

QT默认的日志内容是输出到终端的不会输出到文件里面 (如果想要发给别人可以储存函数),如果需要将日志内容输出到文件中我们需要通过qInstallMessageHandler设置日志信息处理函数。使用方法如下:

  • qinstallmessagehandler
  • qsetmessagepartten
cpp 复制代码
#include <QApplication>
#include <QFile>
#include <QTextStream>
//日志消息的处理函数
void logmessageHander(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
    //获取格式化的日志信息
    QString typeStr = qFormatLogMessage(type,context,message);
    //可以根据日志的级别进行过滤(比如不想要Debug输出,可以直接reutrn)
    QString levelText;
    switch (type) {
    case QtDebugMsg:
        levelText = "Debug";
       	//return;	//加上return之后就不会打印debug日志了          
        break;
    case QtInfoMsg:
        levelText = "Info";
        break;
    case QtWarningMsg:
        levelText = "Warning";
        break;
    case QtCriticalMsg:
        levelText = "Critical";
        break;
    case QtFatalMsg:
        levelText = "Fatal";
        break;
    }
    //写文件代码的时候要动脑子,不要一直想看答案
    QFile file("myapp.log");
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream textStream(&file);
    textStream << typeStr << "\n";
}
int main(int argc,char*argv[])
{
    QCoreApplication app(argc, argv);
    qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} [%{type}]%{if-warning}[%{function}]%{endif}%{if-fatal}[%{function}--%{line}]%{endif}:%{message}");
    qInstallMessageHandler(logmessageHander);
    qDebug() << "debuginfo occured";
    qInfo() <<  "call other function";
    qWarning() << "doesn't work";
    qFatal("fatal error");
    return app.exec();
}

如果需要关闭日志输出,取消之前注册的日志处理函数,我们可以调用qInstallMessageHandler(nullptr);

日志输出对象信息

在调试一些复杂对象的时候,我们需要输出对象的成员信息到日志当中 。但是默认情况下qt的日志库是不支持输出自定义对象的。这时候我们可以通过重写操作符实现对自定义象的日志输出。使用方法如下:

cpp 复制代码
class Person
{
public:
    QString name;
    quint8   age;
    
    // 重写操作符对象
    inline friend QDebug operator<<(QDebug debug,const Person& person)
    {
        debug << "Person("<<person.name<<","<<person.age<<")";
        return debug;
    }
};

int main(int argc,char*argv[])
{
    QCoreApplication app(argc, argv);

    Person person{"maye",18};
    qDebug() << person;

    return app.exec();
}

禁用输出

在开发或者调试时,我们必须借助日志来进行判断,但是当程序需要发布时,调试的日志信息将不再需要,此时如果把代码删除,又不太方便,万一出bug了,又需要调试了呢?

所以Qt提供了禁用qInfoqWarningqDebug输出的宏,qCriticalqFatal是错误不能屏蔽!

在CMakeLists.txt文件中添加如下三行,即可禁用 qInfoqWarningqDebug的输出。

cmake 复制代码
add_compile_definitions(QT_NO_INFO_OUTPUT)
add_compile_definitions(QT_NO_DEBUG_OUTPUT)
add_compile_definitions(QT_NO_WARNING_OUTPUT)
#或
add_compile_definitions(
    QT_NO_INFO_OUTPUT
    QT_NO_DEBUG_OUTPUT
    QT_NO_WARNING_OUTPUT)

3. 字符串类型

C => char*

C++ => std::string

Qt => QByteArray, QString,这个挺好用的,比std::string封装更多,且可以转化为std::string风格

3.1 QByteArray

在Qt中QByteArray可以看做是C语言中 **char***的升级版本。我们在使用这种类型的时候可通过这个类的构造函数申请一块动态内存,用于存储我们需要处理的字符串数据。

下面给大家介绍一下这个类中常用的一些API函数,大家要养成遇到问题主动查询帮助文档的好习惯

注意几个函数

  • sliced(分配)
  • 类型转换
  • 子串判断
  • split(替换字符)
  • 数据操作
  • 其他:文档,或者AI,👀 记不住

构造函数

c++ 复制代码
// 构造空对象, 里边没有数据
QByteArray::QByteArray();
// 将data中的size个字符进行构造, 得到一个字节数组对象
// 如果 size==-1 函数内部自动计算字符串长度, 计算方式为: strlen(data)
QByteArray::QByteArray(const char *data, int size = -1);
// 构造一个长度为size个字节, 并且每个字节值都为ch的字节数组
QByteArray::QByteArray(int size, char ch);

数据操作

c++ 复制代码
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::append(const QByteArray &ba);
void QByteArray::push_back(const QByteArray &other);

// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::prepend(const QByteArray &ba);
void QByteArray::push_front(const QByteArray &other);

// 插入数据, 将ba插入到数组第 i 个字节的位置(从0开始)
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::insert(int i, const QByteArray &ba);

// 删除数据
// 从大字符串中删除len个字符, 从第pos个字符的位置开始删除
QByteArray &QByteArray::remove(int pos, int len);
// 从字符数组的尾部删除 n 个字节
void QByteArray::chop(int n);
// 从字节数组的 pos 位置将数组截断 (前边部分留下, 后边部分被删除)
void QByteArray::truncate(int pos);
// 将对象中的数据清空, 使其为null
void QByteArray::clear();

// 字符串替换
// 将字节数组中的 子字符串 before 替换为 after
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &after);

子字符串查找和判断

c++ 复制代码
// 判断字节数组中是否包含子字符串 ba, 包含返回true, 否则返回false
bool QByteArray::contains(const QByteArray &ba) const;
bool QByteArray::contains(const char *ba) const;
// 判断字节数组中是否包含子字符 ch, 包含返回true, 否则返回false
bool QByteArray::contains(char ch) const;

// 判断字节数组是否以字符串 ba 开始, 是返回true, 不是返回false
bool QByteArray::startsWith(const QByteArray &ba) const;
bool QByteArray::startsWith(const char *ba) const;
// 判断字节数组是否以字符 ch 开始, 是返回true, 不是返回false
bool QByteArray::startsWith(char ch) const;

// 判断字节数组是否以字符串 ba 结尾, 是返回true, 不是返回false
bool QByteArray::endsWith(const QByteArray &ba) const;
bool QByteArray::endsWith(const char *ba) const;
// 判断字节数组是否以字符 ch 结尾, 是返回true, 不是返回false
bool QByteArray::endsWith(char ch) const;

遍历

c++ 复制代码
// 使用迭代器
iterator QByteArray::begin();
iterator QByteArray::end();

// 使用数组的方式进行遍历
// i的取值范围 0 <= i < size()
char QByteArray::at(int i) const;
char QByteArray::operator[](int i) const;

查看字节数

c++ 复制代码
// 返回字节数组对象中字符的个数
int QByteArray::length() const;
int QByteArray::size() const;
int QByteArray::count() const;

// 返回字节数组对象中 子字符串ba 出现的次数
int QByteArray::count(const QByteArray &ba) const;
int QByteArray::count(const char *ba) const;
// 返回字节数组对象中 字符串ch 出现的次数
int QByteArray::count(char ch) const;

类型转换

c++ 复制代码
// 将QByteArray类型的字符串 转换为 char* 类型
char *QByteArray::data();
const char *QByteArray::data() const;

// int, short, long, float, double -> QByteArray
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::setNum(int n, int base = 10);
QByteArray &QByteArray::setNum(short n, int base = 10);
QByteArray &QByteArray::setNum(qlonglong n, int base = 10);
QByteArray &QByteArray::setNum(float n, char f = 'g', int prec = 6);
QByteArray &QByteArray::setNum(double n, char f = 'g', int prec = 6);
[static] QByteArray QByteArray::number(int n, int base = 10);
[static] QByteArray QByteArray::number(qlonglong n, int base = 10);
[static] QByteArray QByteArray::number(double n, char f = 'g', int prec = 6);

// QByteArray -> int, short, long, float, double
int QByteArray::toInt(bool *ok = Q_NULLPTR, int base = 10) const;
short QByteArray::toShort(bool *ok = Q_NULLPTR, int base = 10) const;
long QByteArray::toLong(bool *ok = Q_NULLPTR, int base = 10) const;
float QByteArray::toFloat(bool *ok = Q_NULLPTR) const;
double QByteArray::toDouble(bool *ok = Q_NULLPTR) const;

// std::string -> QByteArray
[static] QByteArray QByteArray::fromStdString(const std::string &str);
// QByteArray -> std::string
std::string QByteArray::toStdString() const;

// 所有字符转换为大写
QByteArray QByteArray::toUpper() const;
// 所有字符转换为小写
QByteArray QByteArray::toLower() const;

3.2 QString

QString也是封装了字符串, 但是内部的编码为utf8, UTF-8属于Unicode字符集, 它固定使用多个字节(window为2字节, linux为3字节)来表示一个字符,这样可以将世界上几乎所有语言的常用字符收录其中。

下面给大家介绍一下这个类中常用的一些API函数。

QStringQByteArray不同的是QByteArray没有经过编码,储存的是字节数(在utf8下)输出字节数。不会进行编码,输出底层,除非调用函数。偏向底层,用于流

QString输出的是字符个数,经过编码,所以应用起来方便

  • indexOf(查找子串,返回位置)

构造函数

c++ 复制代码
// 构造一个空字符串对象
QString();
// 将 char* 字符串 转换为 QString 类型
QString(const char *str);
// 将 QByteArray 转换为 QString 类型
QString(const QByteArray &ba);
// 其他重载的同名构造函数可参考Qt帮助文档, 此处略

数据操作

c++ 复制代码
// 尾部追加数据
QString& append(const QString &str);
QString& append(const char *str);
QString& append(const QByteArray &ba);
void push_back(const QString &other);

// 头部添加数据
QString& prepend(const QString &str);
QString& prepend(const char *str);
QString& prepend(const QByteArray &ba);
void QString::push_front(const QString &other);

// 插入数据, 将 str 插入到字符串第 position 个字符的位置(从0开始)
QString& insert(int position, const QString &str);
QString& insert(int position, const char *str);
QString& insert(int position, const QByteArray &str);

// 删除数据
// 从大字符串中删除len个字符, 从第pos个字符的位置开始删除
QString& remove(int position, int n);

// 从字符串的尾部删除 n 个字符
void  chop(int n);
// 从字节串的 position 位置将字符串截断 (前边部分留下, 后边部分被删除)
void  truncate(int position);
// 将对象中的数据清空, 使其为null
void  clear();

// 字符串替换
// 将字节数组中的 子字符串 before 替换为 after
// 参数 cs 为是否区分大小写, 默认区分大小写
QString& replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);

子字符串查找和判断

c++ 复制代码
// 参数 cs 为是否区分大小写, 默认区分大小写
// 其他重载的同名函数可参考Qt帮助文档, 此处略

// 判断字符串中是否包含子字符串 str, 包含返回true, 否则返回false
bool  contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 判断字符串是否以字符串 ba 开始, 是返回true, 不是返回false
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 判断字符串是否以字符串 ba 结尾, 是返回true, 不是返回false
bool endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

遍历

c++ 复制代码
// 使用迭代器
iterator  begin();
iterator  end();

// 使用数组的方式进行遍历
const QChar  at(int position) const
const QChar  operator[](int position) const;

查看字节数

c++ 复制代码
// 返回字节数组对象中字符的个数
int  length() const;
int  size() const;
int  count() const;

// 返回字节串对象中 子字符串 str 出现的次数
// 参数 cs 为是否区分大小写, 默认区分大小写
int  count(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

类型转换

c++ 复制代码
// int, short, long, float, double -> QString
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString& setNum(int n, int base = 10);
QString& setNum(short n, int base = 10);
QString& setNum(long n, int base = 10);
QString& setNum(float n, char format = 'g', int precision = 6);
QString&QString::setNum(double n, char format = 'g', int precision = 6);
[static] QString QString::number(long n, int base = 10);
[static] QString QString::number(int n, int base = 10);
[static] QString QString::number(double n, char format = 'g', int precision = 6);

// QString -> int, short, long, float, double
int QString::toInt(bool *ok = Q_NULLPTR, int base = 10) const;
short QString::toShort(bool *ok = Q_NULLPTR, int base = 10) const;
long QString::toLong(bool *ok = Q_NULLPTR, int base = 10) const
float QString::toFloat(bool *ok = Q_NULLPTR) const;
double QString::toDouble(bool *ok = Q_NULLPTR) const;


// 所有字符转换为大写
QString QString::toUpper() const;
// 所有字符转换为小写
QString QString::toLower() const;

字符串格式化(重要)

C语言中有sprintf()函数,QString也提供了一个asprintf()函数。

cpp 复制代码
 QString res =  asprintf("fileName:%s size:%d","./av.jpg",20);
 qDebug()<<res<<endl;

不过QString还提供的另一种格式化字符串输出的函数arg(),更为方便。

c++ 复制代码
QString arg(const QString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char( ' ' )) const;
QString arg(int a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char( ' ' )) const;
//用于填充字符串中的%1,%2...为给定格式的整形数字,其中第一个参数是要填充的数字,第二个参数为最小宽度,第三个参数为进制,第四个参数为当原始数字长度不足最小宽度时用于填充的字符

// 示例程序
QString str =  QString("%1 %2 %3").arg(1).arg(2);  //顺序由 %1/2......决定
str = str.arg("hello");
qDebug()<<str<<endl;     //"hello 2 1"

//arg有很多重载
QString text = QString("%1:%2:%3").arg(1,2,10,QChar('0')).arg(35).arg(59);
qDebug()<<text<<endl;    //"01:35:59"

不同字符串类型相互转换(重要)

cpp 复制代码
// std::string -> QString
[static] QString QString::fromStdString(const std::string &str);
// QString -> std::string
std::string QString::toStdString() const;

#QString -> QByteArray
// 转换为本地编码, 跟随操作系统
QByteArray QString::toLocal8Bit() const;
// 转换为 Latin-1 编码的字符串 不支持中文
QByteArray QString::toLatin1() const;
// 转换为 utf8 编码格式的字符串 (常用)
QByteArray QString::toUtf8() const;

#QByteArray -> QString
//使用QString的构造函数即可

4. QVariant

QVariant(变体数据类型)这个类很神奇可以保存很多Qt的数据类型,包括QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、 QPalette、QPen、QPixmap、QPoint、QRect、QRegion、QSize和QString,并且还有C++基本类型,如 int、float等,并且可以转换。

4.1 标准类型

  • 将标准类型转换为QVariant类型
c++ 复制代码
// 这类转换需要使用QVariant类的构造函数, 由于比较多, 大家可自行查阅Qt帮助文档, 在这里简单写几个
QVariant(int val);
QVariant(bool val);
QVariant(double val);
QVariant(const char *val);
QVariant(const QByteArray &val);
QVariant(const QString &val);
......
    
// 使用设置函数也可以将支持的类型的数据设置到QVariant对象中
// 这里的 T 类型, 就是QVariant支持的类型
void setValue(const T &value);
// 该函数行为和 setValue() 函数完全相同----------------------------->自定义类型
[static] QVariant fromValue(const T &value);

Exmple

cpp 复制代码
QVariant v(5);

QVariant v;
v.setValue(5);

QVariant v = QVariant::fromValue(5);

int i = v.toInt();          // i is now 5
QString s = v.toString();   // s is now "5"
  • 判断 QVariant中封装的实际数据类型

Type 是枚举类型

c++ 复制代码
//获取类型,返回的是一个枚举类型;如QVariant::Int ...
Type type() const;
//获取类型名
const char *typeName() const;
//根据类型id(枚举)获取类型名(字符串)
[static] const char *typeToName(int typeId);
//根据类型名(字符串)获取类型id(枚举)
[static] Type nameToType(const char *name);
  • 将QVariant对象转换为实际的数据类型
c++ 复制代码
//在转换之前可以先判断能够转换成对应的类型
bool canConvert(int targetTypeId) const
bool canConvert() const

bool 		toBool() const;
QByteArray 	toByteArray() const;
double 		toDouble(bool *ok = Q_NULLPTR) const;
float 		toFloat(bool *ok = Q_NULLPTR) const;
int 		toInt(bool *ok = Q_NULLPTR) const;
QString 	toString() const;
......

T value() const
//v.value<int>();       
相关推荐
自激振荡器2 小时前
第二天:IIC总线协议
单片机·嵌入式·通信协议·iic总线协议
陈随易2 小时前
Vue-Router v5内置文件式路由,告别手写维护的恐惧
前端·后端·程序员
木卫二号Coding2 小时前
Python-文件拷贝+文件重命名+shutil+记录
开发语言·python
bubiyoushang8882 小时前
基于Q-learning的路径规划MATLAB仿真程序实现
开发语言·matlab
FAFU_kyp3 小时前
Rust 结构体(struct)
开发语言·后端·rust
努力写代码的熊大3 小时前
深入探索C++关联容器:Set、Map、Multiset与Multimap的终极指南及底层实现剖析
开发语言·c++
枫叶梨花3 小时前
SpringBoot+Vue实现SM4加密传输
spring boot·后端
悟空码字3 小时前
SpringBoot整合MyBatis-Flex保姆级教程,看完就能上手!
java·spring boot·后端
J_liaty3 小时前
Java工程师的JVM入门教程:从零理解Java虚拟机
java·开发语言·jvm