Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

Qt多种定时器

发表于 2019-07-13

介绍Qt的三种定时器QObject内部定时器,QBasicTimer,QTimer。

QObject内部定时器

  使用startTimer开启定时器,使用killTimer(int id)接口来关闭指定的定时器。
  启动定时器后会在对应间隔时间触发timerEvent事件。
  示例:

1
2
3
4
5
6
7
8
9
10
11
class Object : public QObject {
Q_OBJECT
public:
Object()
{
startTimer(1000);
}

protected:
void timerEvent(QTimerEvent *event) { }
};

QBasicTimer

  QBasicTimer类为对象提供定时器事件。
  QBasicTimer特点快速、轻量级和低级类。对于需要降低使用多个定时器开销的应用程序,QBasicTimer可能是一个不错的选择。如果是一般使用情况建议使用更高级别的QTimer类而不是此类。
  使用start接口来设置定时时间与定时事件的接收对象。
  示例:

1
2
3
4
5
6
7
8
class Object : public QObject {
Q_OBJECT
public:
Object() { }

protected:
void timerEvent(QTimerEvent *event) { }
}

1
2
3
Object object;
QBasicTimer basicTimer;
basicTimer.start(500, &object);

QTimer

  QTimer类提供重复和单次定时器。
  QTimer类为定时器提供高级编程接口。创建一个QTimer实例,将其timeout()信号连接到对应的槽中,然后调用start()开启定时器,每隔一段时间会发出timeout()信号。
  示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Object : public QObject {
Q_OBJECT
public:
Object()
{
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer.start(1000);
}

private slots:
void onTimeout() { }

private:
QTimer m_timer;
};

定时器小知识

  • 需要不同时间精度的定时器,可以指定定时器的TimerType类型。
Qt::TimerType 解释
Qt::PreciseTimer 精确的定时器试图保持毫秒精度
Qt::CoarseTimer 粗略的定时器试图将精度保持在所需间隔的5%以内
Qt::VeryCoarseTimer 非常粗略的定时器

  特别地Qt::VeryCoarseTimer非常粗略的意思是精度为±500ms。例如,10500ms的间隔将四舍五入为11000ms,而10400ms会置为10000ms。

  • 上述定时器例子都为循环触发,需要停止定时器请使用stop或killTimer,而想使用单次定时器最好使用QTimer::singleShot接口。
  • 使用QObject::timerEvent捕获定时器事件,如果存在多个定时器源,可以使用timerId来判断确定那个定时器事件。
  • 如果系统忙或无法提供请求的准确性,所有定时器类型都有可能会比预期的时间晚超时。在这种晚超时的情况下,虽然是多个超时已经过期,但是只发出一次超时事件。
  • QTimer的remainingTime接口可以获得距离触发定时器事件的剩余时间。
  • 使用QObject的startTimer需要注意的是每调用一次会新增一个定时器并返回一个定时器ID。

    1
    2
    3
    id1 = startTimer(1000); // 开启一个1秒定时器,返回其定时器ID
    id2 = startTimer(2000); // 开启一个2秒定时器,返回其定时器ID
    id3 = startTimer(3000); // 开启一个3秒定时器,返回其定时器ID
  • Qt官方使用定时器的例子可以参考Analog Clock Example。
    Analog Clock Example


  • 本文首发于公众号:Qt君

Qt注册自定义类型到元对象中

发表于 2019-07-12

本文讲述如何注册自定义类型到Qt元对象系统中和它有什么作用。

注册自定义结构体为例

  1. 使用Q_DECLARE_METATYPE标记自定义类型;

    1
    2
    3
    4
    5
    6
    7
    #include <QMetaType>
    struct MyStruct {
    QString name;
    QString color;
    };

    Q_DECLARE_METATYPE(MyStruct)
  2. 在main函数中使用qRegisterMetaType注册自定义类型到元对象系统中。

    1
    2
    3
    4
    5
    6
    int main(int argc, char *argv[]) {
    ...
    qRegisterMetaType<MyStruct>();
    ...
    return 0;
    }

作用

  • 被Q_DECLARE_METATYPEQ标记的类型可以让QMetaType查询到类型,也可以让QVariant识别到。例如:

    1
    2
    3
    4
    5
    6
    MyStruct myStruct;
    QVariant variant;
    variant.setValue(myStruct); // 不使用Q_DECLARE_METATYPEQ标记的自定义类型会出现编译错误。
    ...
    MyStruct myStruct2 = variant.value<MyStruct>();
    ...
  • 使用qRegisterMetaType注册自定义类型到元对象系统中主要作用为QObject的属性系统(信号槽)中使用该自定义类型。

函数禁用delete与替代函数体定义default

发表于 2019-07-11

介绍delete与default在函数中的使用方法。

函数禁用delete

  在函数声明后加入=delete即可将该函数标记,一旦被调用则会导致编译错误。
  例如:

1
2
3
4
5
struct Test {
void* operator new(std::size_t) = delete;
void* operator new[](std::size_t) = delete;
};
Test *p = new Test; // 编译错误

替代函数体定义dafault

  在函数声明后加入=default即可替代函数体进行定义,适用范围类的特殊成员函数,且该特殊成员函数没有默认参数。
  例如:

1
2
3
4
class Test {
public:
Test() = default;
};

  等价于:

1
2
3
4
5
6
class Test {
public:
Test()
{
}
};

参考

1
2
https://en.cppreference.com/w/cpp/language/member_functions#Special_member_functions
https://en.cppreference.com/w/cpp/language/function#Deleted_functions

Qt之JSON教程-实战篇

发表于 2019-07-10

以实战例子讲述JSON三兄弟的后续故事。

实战一:发送JSON网络请求

  作为JSON老大哥的QJsonValue自知对面的大户人家妹子貌美如花,心里已经打起算盘,先下手为强,后下手遭殃。决定显示下自己的家底,想起这件事,老大哥回想到5年前错过的妹子,当时妹子说我们不适合,大哥问,我对你还不够好么。但妹子说了一句让老大哥彻底伤心的话。做我的男朋友要有QQ会员,可惜你不是。

  老大哥找了QNetworkAccessManager以json的方式发送自己的QQ会员和账号,以表明自己的诚意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
QJsonArray jsonArray;
jsonArray<<1<<2<<3;

QJsonObject jsonObject;
jsonObject["account"] = "xxxxx";
jsonObject["vip"] = "8";
jsonObject["array"] = jsonArray;

QNetworkAccessManager manager;
QNetworkRequest request(QUrl("https://www.example.com"));
request.setRawHeader("Content-Type", "application/json");

QNetworkReply* reply = manager.post(request,
QJsonDocument(jsonObject).toJson());
QEventLoop eventLoop;
QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec(); // 进入等待返回,但ui事件循环依然进行。

QByteArray result = reply->readAll();
qDebug()<<result;

  躲着墙角的二哥QJsonObject看到了老大哥的一举一动,暗暗窃喜,还好我也是QQ会员,于是在发送数据处做了些小修改以彰显自己的QQ会员等级。

1
2
3
4
5
6
7
QNetworkReply* reply = manager.post(request, R"(
{
"account": "xxxxx",
"vip": "8",
"array": [1, 2, 3]
}
)");

  看起来简单明了,妹子肯定是我的了。二哥,心里暗暗窃喜。

  螳螂捕蝉黄雀在后,三弟QJsonArray手拿银子默念,大哥和二哥都不让下弟弟的,尽是QQ会员,还好我不赖,昨天问了爹爹拿钱充了vip8。三弟也发自己的QQ会员过去了,只是方式略有个性。

1
2
QNetworkReply* reply = manager.post(request, 
"{\"account\":\"xxxxx\",\"vip\":\"8\",\"array\":[1,2,3]}");

  三兄弟按照昨天约定的时间到村口客栈见面。看到妹子赶紧走上前表示自己的QQ会员等级有多高,大哥还没说出话来就被大妹子打断了,说你装载JSON数据麻烦!转头又说二哥虽然简洁,但过于占地方。三弟自然看到面前这么凶恶的妹子,自然不敢说话低着头说,数据反斜杠转义过多,不利于数据操作。

  三兄弟非常灰心,原来QQ会员也帮不到我了。

实战二:读写json格式的配置文件

  老大哥垂头丧气说,QQ会员也没有用了呀,仍了可惜,不如我们埋了它,当是埋葬我们逝去的青春。二哥三弟听后感动得不要不要的,就赶紧拿了家里祖传的铲子挖泥了。他们将QQ信息放(写)在一个叫config.json的酒壶里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
QJsonObject jsonObject;
jsonObject["account"] = "xxxxx";
jsonObject["password"] = "xxxxx"
jsonObject["vip"] = "8";
QJsonArray jsonArray { 1, 2, 3 };

jsonObject["array"] = jsonArray;
QFile file("config.json");
if (! file.open(QIODevice::WriteOnly)) {
qDebug()<<"文件打开失败。";
return false;
}

QByteArray data = QJsonDocument(jsonObject).toJson();
file.write(data);
file.close();

  一天晚上管家拿着铲子在挖泥,手里捧着他们三兄弟前几天放的青春。管家碎碎念说了一句,终于拿到你们的QQ了,还是会员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
QFile file("config.json");
if (! file.open(QIODevice::ReadOnly)) {
qDebug()<<"文件打开失败。";
return false;
}

QByteArray data = file.readAll();
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error != QJsonParseError::NoError) {
qDebug()<<"Json文件解析错误。";
return false;
}

if (jsonDoc.isObject()) {
QJsonObject jsonObject = jsonDoc.object();
qDebug()<<jsonObject;
}
else if (jsonDoc.isArray()) {
QJsonArray jsonArray = jsonDoc.array();
qDebug()<<jsonArray;
}
else {
qDebug()<<"Json文件解析为空。";
}

file.close();


  • 文章首发于微信公众号:Qt君

使用Qt接口获取Windows系统的事件

发表于 2019-07-09

介绍Qt4和Qt5获取Windows系统事件的方法。

Qt4版本的实现

方法1:

  • 通过继承QWidget的类中重新实现winEvent接口,以接收在消息参数中传递的本机Windows事件。
    1
    bool QWidget::winEvent(MSG *message, long *result)

方法2:

  • 通过继承QCoreApplication的类中重新实现winEventFilter接口,以接收在消息参数中传递的本机Windows事件。
    1
    bool QCoreApplication::winEventFilter(MSG *msg, long *result)

Qt5版本实现

方法1:

  • 通过继承QWidget的类中重新实现winEvent接口,以接收在消息参数中传递的eventType标识的本机平台事件。
    1
    bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)

方法2:

  • 通过继承QAbstractNativeEventFilter的类中重新实现nativeEventFilter接口:
    1
    bool QAbstractNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)

并安装到中:

1
void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)

或安装到:

1
void QAbstractEventDispatcher::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)

  • 特别地:不同平台对应的eventType类型有:
平台 事件类型(eventType) 消息类型(message) 结果类型(result)
Windows “windows_generic_MSG” MSG * LRESULT
macOs “NSEvent” NSEvent * 无
XCB(Linux) “xcb_generic_event_t” xcb_generic_event_t * 无

分享一个接口测试应用postman

发表于 2019-07-08

postman可以调试与发送网页HTTP请求,使用方便,且支持平台丰富,支持的平台有windows,mac,linux系统,还可以通过Google Chrome安装postman插件。

下载使用

  • 官网:

    1
    https://www.getpostman.com/
  • 下载地址:

    1
    https://www.getpostman.com/downloads/
  • Google Chrome浏览器可在扩展程序处搜索postman安装。

使用

  • 选择需要发送请求的类型;
  • 可以设置Params,采用的是key/value设置;
  • 可以设置Authorization;
  • 可以设置Headers;
  • 可以设置Body等等。

1.png

代码转换器功能

  postman还有一个比较有用的功能,就是可视化输入请求数据后可以转换对应的网络请求代码。

  点击网络请求界面的橙色字code即可进入代码转换器。
2.png

  从看下图可以看到转换的代码有很多,只列出一部分。
3.png

  比如选择C(LibCurl),然后复制代码到我们程序里面就可以了。用起来也挺方便的。
4.png

更多功能

  • 支持抓包、保存历史记录、多终端同步等更多功能。

Qt之JSON教程-使用篇

发表于 2019-07-07

以故事方式来学习如何使用Qt接口来操作JSON数据。

JSON三兄弟

老大哥QJsonValue

  • 主要用于封装JSON值,类似于QVariant。
    它能够存储以下值:
类型 QJsonValue类型
bool QJsonValue::Bool
double QJsonValue::Double
string QJsonValue::String
array QJsonValue::Array
object QJsonValue::Object
null QJsonValue::Null
  • 与QVariant互转

    1
    2
    QJsonValue fromVariant(const QVariant &variant)
    QVariant QJsonValue::toVariant() const
  • 可以与QJsonObject,QJsonArray互转

    1
    2
    3
    4
    5
    QJsonValue::QJsonValue(const QJsonArray &a)
    QJsonObject QJsonValue::toObject() const

    QJsonValue::QJsonValue(const QJsonObject &o)
    QJsonArray QJsonValue::toArray() const

二哥QJsonObject

  • 负责封装JSON对象,是键/值对列表,其中键是惟一的字符串,值由QJsonValue表示。
  • QJsonObject与QVariantMap可以互相转换。
  • 接口与QMap相似,都具有size()、insert()和remove()等操作,还可以使用标准C++迭代器模式对其内容进行迭代。
  • 直接构造使用:

    1
    2
    3
    4
    5
    6
    7
    QJsonObject jsonObject
    {
    {"key1", 1},
    {"key2", 6.6},
    {"key3", "Hello world"},
    {"array", QJsonArray({1, 2, 3})}
    };
  • 类似于QVariantMap操作:

    1
    2
    3
    4
    5
    QJsonObject jsonObject;
    jsonObject["key1"] = 1;
    jsonObject["key2"] = 6.6;
    jsonObject.insert("key3", "Hello world");
    jsonObject["array"] = QJsonArray({1, 2, 3});
  • 与QVariantMap互相转换

    1
    2
    QJsonObject fromVariantMap(const QVariantMap &map)
    QVariantMap QJsonObject::toVariantMap() const
  • 还可以与QVariantHash互相转换,操作类似QVariantMap转换。

三弟QJsonArray

  • 负责封装JSON数组,JSON数组是一个值列表,接口与QVariantList类似,QJsonArray与QVariantList可以互相转换。
  • QJsonList操作于QList相似,都具有size()、insert()和removeAt()等操作,还可以使用标准的C++迭代器模式对其内容进行迭代。

  • 直接赋值使用:

    1
    QJsonArray jsonArray = { 1, 6.6, QString("Hello world") };
  • 接口操作使用:

    1
    2
    3
    4
    QJsonArray jsonArray;
    jsonArray.append(1);
    jsonArray.append(6.6);
    jsonArray.insert(2, "Hello world");
  • 与QVariantList互相转换:

    1
    2
    QJsonArray fromVariantList(const QVariantList &list)
    QVariantList QJsonArray::toVariantList() const

JSON管家

  一天,三兄弟玩得甚欢,管家有些烦恼,三兄弟年龄不小了,还整天捣蛋,苦不堪言,是时候帮它们解决人生大事了,让他们得老婆来管这三兄弟。管家暗暗窃喜。老夫赶紧将他们的资料(数据)转换为字符串发给对面Web端的大户人家先。

  管家拿出QJsonDocument工具转换他们三兄弟的资料。

1
2
3
4
QJsonDocument(const QJsonObject &object)
QJsonDocument(const QJsonArray &array)

QByteArray toJson() const

  分别将QJsonObject与QJsonArray转换为QByteArray。

1
2
QByteArray byteArray1 = QJsonDocument(jsonObject).toJson();
QByteArray byteArray2 = QJsonDocument(jsonArray).toJson();

  管家看了看,拿到资料了,不知道资料是否正确,还是要确保一下就使用isNull接口验证:

1
bool QJsonDocument::isNull() const // 如果返回为true则JSON数据解析不正确或为空。

  焦急的管家等了几天,对面Web端怎么会没有答复的。正在焦虑走来走去,是不是资料不够好?还是发送出去格式不好看,看来要给他们弄弄格式,于是就找来了生成字符串的toJson来解决。

  toJson面对焦急得管家自然也不敢怠慢,立马给出解决方案。

1
QByteArray toJson(QJsonDocument::JsonFormat format) const

  • JsonFormat::Indented(缩进型)

    1
    2
    3
    4
    {
    "key1": 1,
    "key2": 6.6
    }
  • JsonFormat::Compact(紧凑型)

    1
    {"key1":1,"key2":6.6}

  管家修改了一下格式发出去,很快就收到对面妹子发送过来资料数据了,要快快解析看看。

  管家先将QByteArray数据转换为QJsonDocument对象,然后再转换为QJsonObject或QJsonArray即可。

1
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = nullptr)

  管家看了看,老夫还是有点效果的。

1
QJsonDocument jsonDoc = QJsonDocument::fromJson("{\"address\":\"村口客栈见\",\"note\":\"带点吃的\"}");

JSON背锅者

  管家又接收到了一封信,可是解析不出来,正在头皮发麻着思考到底是那一步出错了。

  突然跳出一个人QJsonParseError说:管家这锅我来背,我帮你找出问题,但我又一个小小得要求,就是你也给我介绍介绍。

  管家无奈只好答应。

1
2
3
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson("{\"note\":\"二哥有点帅\"}", &jsonError);
qDebug()<<jsonError.errorString();

  小子你可以啊,原来fromJson还有这操作。

后续

  管家将此事告诉他们三兄弟,如获珍宝一样。老大哥还说,看来我单身30年就要终结了。二哥则表示要在妹子面前露一手,三弟也不甘示弱赶紧去问老爹准备点钱。

  后续他们三兄弟结局如何?,是否抱得美人归?请关注下篇Qt之JSON教程-实战篇。


  • 文章首发于微信公众号:Qt君

Qt之JSON教程-介绍篇

发表于 2019-07-06

JSON是JavaScript Object Notation的简称,同时也是一种轻量级的数据交换格式。其特点为易于人阅读和编写,同时也易于机器解析和生成,广泛应用于web端数据网络传输。其中Qt5引入了对JSON数据的支持。

插图

JSON数据类型

  • bool
  • double
  • string
  • array
  • object
  • null

JSON格式规则

  • 布尔值由JSON中的true或false表示;
  • 由于JSON没有明确指定数值的有效范围,但Qt中的支持仅限于double-双精度的有效范围和精度;
  • 字符串可以是任何有效的unicode字符串;
  • 数组是值列表,表示方法为方括号包含的内容[...];
  • 对象是键/值对的集合,表示方法为花括号包含的内容{...};
  • 对象中的所有键都是字符串,对象不能包含任何重复键;
  • 对象中的键和值之间的分隔符是冒号:。

Qt有关JSON的类

Qt JSON类 解释
QJsonArray 封装JSON数组
QJsonDocument 读取和写入JSON文档的方法
QJsonParseError 用于报告JSON解析过程中的错误
QJsonObject 封装JSON对象
QJsonValue 用JSON封装一个值

JSON例子

1
2
3
4
5
6
7
8
9
10
11
{
"enable": true,
"length": 10,
"precision": 0.1,
"name": "Car",
"array": [1, 2, 3],
"province": {
"city": "黑龙江"
},
"what": null
}

一些检验工具

  • 在线检验工具BeJson,SoJson,json.cn。

Windows系统快速查找文件

发表于 2019-07-05

使用系统界面的查找文件往往较慢,今天教大家如何使用CMD控制台快速查找到自己需要的文件。

插图

步骤

  1. 按快捷键ctrl + r;
  2. 输入cmd确定后会出现控制台;
  3. 命令行输入dir /S 你需要查找的文件(会在当前目录下递归查找文件并显示具体信息);

命令解释

  • dir命令为查看文件;
  • dir的/S参数为显示指定目录和所有子目录中的文件。

一些额外知识

  • 切换盘符路径
    例如切换到D盘需要这样操作cd /d d:。

  • 切换当前盘的路径
    例如切换到C:\Users目录需要这样操作cd C:\Users。

一些例子

  • 查找C盘根目录(包括递归子目录)下的所有test.png文件:
    cd /d c:/
    dir /S test.png

  • 查找C盘根目录下的png格式的文件:
    cd /d c:/
    dir *.png

Qt网络限速

发表于 2019-07-04

通过限制套接字的读取速度从而达到网络限速的作用。

限制TCP速度

  • 设置QTcpSocket的setReadBufferSize接口。
    1
    void QTcpSocket::setReadBufferSize(qint64 size)

限制Http请求的速度

  • 设置QNetworkReply的setReadBufferSize接口。
    1
    void QNetworkReply::setReadBufferSize(qint64 size)

限制WebSocket速度

  • 设置QWebSocket的setReadBufferSize接口。
    1
    void QWebSocket::setReadBufferSize(qint64 size)

限制SslSocket速度

  • 设置QSslSocket的setReadBufferSize接口。
    1
    void QSslSocket::setReadBufferSize(qint64 size)

关于接口

  setReadBufferSize为设置套接字内部读取缓冲区的大小。

  如果缓冲区大小限制为一定的大小,Socket将不会缓冲超过这个大小的数据。异常情况下,缓冲区大小为0意味着读取缓冲区是无限的,所有传入数据都被缓冲。这是默认值。

  如果您只在特定的时间点读取数据(例如,在实时流应用程序中),或者您希望保护套接字不接收过多的数据,而这些数据可能最终导致应用程序耗尽内存,则此选项非常有用。

1…131415…32
Qt君

Qt君

313 日志
41 标签
© 2019 Qt君
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
粤ICP备 - 16070052号