Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

设计模式-流畅接口

发表于 2019-08-12

何为流畅接口?先上代码String(“1”)(“2”)(“3”)(“4”)(“5”)。流畅接口从字面上看是用起来很顺手,究竟是有多顺手,又应用在哪里呢?相信你看完本文多少会有些答案了。

以自定义String类(继承QString)为例。

1
2
3
4
5
6
7
8
class String : public QString {
public:
String() { }
String(const QString &str)
{
append(str);
}
};

当我们需要往String增加字符串时我们常规做法:

1
2
3
4
5
6
String str;
str.append("1");
str.append("2");
str.append("3");
str.append("4");
str.append("5");

感觉上面起来都有些啰嗦,看了下QString文档,QString的append接口调用后返回自己的引用,那么就可以这样写。

1
2
3
4
5
6
String str;
str.append("1")
.append("2")
.append("3")
.append("4")
.append("5");

在这里看来,append接口就是流畅接口了,它避免啰嗦的调用。

头铁君这时候跳出来说,Qt君啊,你还是失算了。我还有更流畅的做法,你看:

1
2
3
4
5
String &operator()(const QString &str)
{
append(str);
return *this;
}

通过String类重载()操作符后我还可以这样做:

1
String("1")("2")("3")("4")("5");

头铁君向我投来得瑟的目光,看得我瑟瑟发抖。

头铁君啊,你别老是这么头铁,看来我要放大招了。你那做法那里是流畅接口的精神啊,看到那么多括号都怕了,你别说这是给别人用?!

头铁君,来看看我的做法吧。

1
2
3
4
5
String &operator<<(const QString str)
{
append(str);
return *this;
}

通过重载<<操作符做出类似管道效果的流畅接口。

1
2
String str;
str << "1" << "2" << "3" << "4" << "5";

头铁君看了不感惊叹,还真是比我那堆括号好用啊。就是看起来有些眼熟的呀。哦,对了。原来和qDebug()原理相似的呀。

1
qDebug() << "1" << "2" << "3" << "4" << "5";

头铁君出了名是头铁,还有其他的应用场合吗?

来来来,别急。我们再看下QString的arg()接口的使用。

1
2
3
4
5
6
7
QString fileName;
QString size;
QString md5;
QString status = QString("File Info: file name: %1; size: %2; checksum md5: %3")
.arg(fileName)
.arg(size)
.arg(md5);

头铁君若有所思一会,立马打开电脑查了起来。看着头铁君桌面的卡布奇诺都凉了,他还在查。看起来冻的卡布奇诺更有味道,感觉就是太甜了。

哦,原来是这样啊。这不就是Builder模式吗?通过返回自己的引用或指针来实现流式(链式)编程。明白了,头铁君抬头看到我喝着他的卡布奇诺,为了避免尴尬,说了一句,今天天气不错哈。

从流畅接口(Builder模式)到只读对象的实现。

Network类只提供获取ip,mask,gateway,dns的方法,而设置方法都被隐藏起来了。而真正实现设置网络属性是通过NetworkBuilder类来进行操作。并可以通过它来体现流畅接口。

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
28
class NetworkBuilder;

class Network {
public:
Network();
static NetworkBuilder builder();

QString ip() const;
QString mask() const;
QString gateway() const;
QString dns() const;

private:
friend NetworkBuilder;
QString m_ip;
QString m_mask;
QString m_gateway;
QString m_dns;
};

class NetworkBuilder {
public:
NetworkBuilder &ip(const QString &ip);
NetworkBuilder &mask(const QString &ip);
NetworkBuilder &gateway(const QString &gateway);
NetworkBuilder &dns(const QString &dns);
Network build();
};

通过NetworkBuilder构建Network属性后通过build的调用返回Network对象。

1
2
3
4
5
Network::builder().ip("192.168.1.1")
.mask("255.255.255.0")
.gateway("192.168.1.1")
.dns("8.8.8.8")
.build();

现实意义:

  • 通过只读对象来限定接口使用者的乱用行为;
  • 明确确定设置参数后需要调用build接口生效,这就意味着可以提醒接口调用者生效了那些参数。
  • 可以体现出清晰明确的编程。
  • 让接口调用者用来顺手(流畅)。

文章首发微信公众号Qt君。

收集一些Qt学习网站

发表于 2019-08-11

Qt君为大家收集一些Qt学习网站。

  • Qt 官网
    https://www.qt.io
    了解Qt最新资讯开发动态的窗口。

  • Qt 资源下载
    http://download.qt.io
    最新Qt安装程序可以在这里找到。

  • Qt 博客者聚集地
    http://planet.qt.io
    很多Qt大神都在里面。

  • Qt 百科
    https://wiki.qt.io
    这里Qt社区收集了多年来关于Qt的信息。

  • Qt 文档
    https://doc.qt.io
    在线版的帮助文档。

  • Qt 论坛
    https://forum.qt.io
    从桌面和移动到云,游戏,工具,第三方库,兴趣小组。

  • Qt 提交Bugs
    https://bugreports.qt.io
    提交Bug前先搜索下Bug是否已经存在。

  • Qt 官方示例
    https://doc.qt.io/qt-5/qtexamples.html
    图文并茂的官方示例。

  • Qt 第三方库聚合
    https://inqlude.org
    如QCustomPlot,QJson,Log4Qt。

  • QtCentre
    http://www.qtcentre.org
    访问较慢且上面的信息很久没更新了,倒是提问题或找解决问题挺有用的。

  • CSDN Qt 论坛
    https://bbs.csdn.net/forums/Qt

  • QTCN网
    http://www.qtcn.org
    上面有很多开源作品。

  • Qt中文开源社区
    http://www.qter.org
    教程论坛文章俱全。

  • 问答论坛stackoverflow
    https://stackoverflow.com
    提问题(网友较热心)或找问题不限于Qt且大多都可以找到。

  • B站视频教程
    https://www.bilibili.com
    想看视频教程学习是个不错的地方。

  • 书籍教程
    https://github.com/justjavac/free-programming-books-zh_CN
    免费的编程中文书籍索引。


  • 你们如果有更多关于Qt学习的网站可以在评论区分享。
  • 本文首发公众号「Qt君」。

避免写头文件后缀的写法

发表于 2019-08-10

避免写头文件后缀的写法(实际没什么意义仅供参考)。

  • 一般我们包含头文件都是以这种形式包含。

    1
    #include "1.h"
  • 下列宏定义可以这样做:

    1
    2
    3
    4
    5
    #define STRING(a) #a
    #define STRING2(a) STRING(a)
    #define JOIN(a, b) a## . ##b
    #define JOIN2(a, b) JOIN(a, b)
    #define HEAD(prefix) STRING2(JOIN2(prefix, h))
1
#include HEAD(1)

编译即崩坏(无用的尝试)

发表于 2019-08-09

尝试添加以下语句编译将会导致编译器无限循环包含而崩溃。

1
#include __FILE__
  • 更多关于#include可查看文章:
    C/C++黑魔法-利用include宏读文件​

Qt之Base64编解码

发表于 2019-08-08

本文介绍如何使用Qt接口对数据进行Base64编解码。

1.介绍

  Base64是基于64个可打印字符来显示2进制数据,它用于传输8Bit字节代码,并在HTTP传输中广泛应用。

1.1 规则

  1. 把3个字符变成4个字符(加两位高位0,数据一次递后)。
  2. 每76个字符加一个换行符。
  3. 最后的结束符也要处理(加等于号)。

1.2 Base64对照表

插图

1.3 示例

  • 转化前:

    1
    1111110,0111111,11111100
  • 把3个字符变成4个字符(加两位高位0):

    1
    00111111,00100111,00111111,00111100
  • 翻译为十进制:

    1
    63,39,63,60
  • 与Base64对照表转译:

    1
    /,n,/,8
  • 最后得出为/n/8

2.编码

  • 接口:

    1
    2
    QByteArray QByteArray::toBase64() const
    QByteArray QByteArray::toBase64(QByteArray::Base64Options options) const
  • 示例:

    1
    2
    3
    QByteArray text("Hello world");
    text.toBase64();
    /* 输出: SGVsbG8gd29ybGQ= */

3.解码

  • 接口:

    1
    2
    3
    [static] QByteArray QByteArray::fromBase64(const QByteArray &base64)
    [static] QByteArray QByteArray::fromBase64(const QByteArray &base64,
    QByteArray::Base64Options options)
  • 示例:

    1
    2
    QByteArray::fromBase64("SGVsbG8gd29ybGQ="); 
    /* 输出: Hello world */

4.关于枚举Base64Options

  • Base64Options枚举值一览表
Base64Options 含义
Base64Encoding (默认)常规Base64字母表,简称“Base64”
Base64UrlEncoding 与常规Base64不同的是将
“+”和“/”分别改成了“-”和“_”,
对url更友好
KeepTrailingEquals (默认)保持编码数据末尾后填充等号,
数据的大小总是4的倍数。
OmitTrailingEquals 省略编码数据末尾的等号
  • 对照示例:
toBase64(Base64Options ) Hello world?!
Base64Encoding SGVsbG8gd29ybGQ/IQ==
Base64Encoding \ OmitTrailingEquals SGVsbG8gd29ybGQ/IQ
Base64UrlEncoding SGVsbG8gd29ybGQ_IQ==
Base64UrlEncoding \ OmitTrailingEquals SGVsbG8gd29ybGQ_IQ

5.关于更多

1
https://tools.ietf.org/html/rfc2045

Qt摄像头热插拔实现

发表于 2019-08-07

基于Qt的Camera模块实现摄像头的热插拔。当只有一个摄像头时,被拔开后再插入能自动恢复相机状态。当有多个摄像头时,拔开当前摄像头会自动设置另外一个摄像头。

基于定时查询的方法

  • 定时查询设备列表变化;

    1
    2
    connect(&m_checkDeviceListTimer, SIGNAL(timeout()), 
    this, SLOT(checkDeviceList()));
  • 如果当前设备列表对比上一次缓存的设备列表有变化则发送设备列表变化事件(信号)deviceListChanged();

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void QtCamera::checkDeviceList()
    {
    QList<QCameraInfo> curCameraInfoList = QCameraInfo::availableCameras();
    if ( m_preCameraInfoList.count() != curCameraInfoList.count() ) {
    emit deviceListChanged();
    }

    m_preCameraInfoList = curCameraInfoList;
    }

单设备重连机制

  • 先前autoRestore()槽函数绑定设备列表变化信号。

    1
    2
    connect(this, SIGNAL(deviceListChanged()), 
    this, SLOT(autoRestore()));
  • 触发自动重连机制。
      当设备存在则会重新启动start();
      当设备不存在则关闭该设备。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void QtCamera::autoRestore()
    {
    if (! m_isStarted) {
    return;
    }

    if (deviceExist(m_curCameraInfo)) {
    if (m_camera->status() != QCamera::ActiveStatus) {
    QTimer::singleShot(500, m_camera, SLOT(start()));
    }
    }
    else {
    if (m_camera->status() == QCamera::ActiveStatus) {
    m_camera->stop();
    m_camera->unload();
    }
    }
    }

多设备自动切换

  • autoSelectDevice()槽函数连接设备列表变化信号。

    1
    2
    connect(this, SIGNAL(deviceListChanged()), 
    this, SLOT(autoSelectDevice()));
  • 当设备已存在再次刷新当前的设备;

  • 当设备被断开,自动切换到第一个设备。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void QtCamera::autoSelectDevice()
    {
    QList<QCameraInfo> curCameraInfoList = QCameraInfo::availableCameras();
    if (curCameraInfoList.isEmpty())
    return;

    if (curCameraInfoList.contains(m_curCameraInfo)) {
    selectDevice(m_curCameraInfo);
    return;
    }

    selectDevice(curCameraInfoList.first());
    }

关于更多

  • 源码地址:

    1
    https://github.com/aeagean/QtCamera
  • 文章首发公众号:Qt君

  • 后续更新摄像头参数选择算法(自动匹配用户设置摄像头参数,分辨率,帧率,格式)。

Qt数字转字符串

发表于 2019-08-06

2进制,8进制,10进制,16进制无保留地转换字符串。

常用转换

  • 使用QString的number接口下列设置会被转换为10进制的字符串,显然不是我们想要的。
    1
    2
    3
    4
    QString::number(0b111); // "7"
    QString::number(0123); // "83"
    QString::number(123); // "123"
    QString::number(0x123); // "291"

保留进制的转换

  • 对number接口添加进制参数让它转换具备进制的字符串,但看起来像10进制的字符串,感觉也不是自己想要的。
    1
    2
    3
    4
    QString::number(0b111, 2);  // "111"
    QString::number(0123, 8); // "123"
    QString::number(123, 10); // "123"
    QString::number(0x123, 16); // "123"

更彻底的转换

  • “#”在宏中的作用为将”#“后的内容转换为字符串。
  • 这样带进制标识的转换看起来好多了。
    1
    2
    3
    4
    5
    #define TO_STR(n) #n
    TO_STR(0b111); // "0b111"
    TO_STR(0123); // "0123"
    TO_STR(123); // "123"
    TO_STR(0x123); // "0x123"

Qt识别文件类型的正确姿势

发表于 2019-08-05

一般我们识别文件类型都是从文件的后缀区分,这样做可以识别出文件格式。但在Qt里有更好的实现方法。

以识别图片类型为例

  一般识别图片类型方法:
虽然这一方法可以实现识别图片类型,但是维护起来相对困难。如果真的要识别所有的文件是否是图片类型,还需要添加更多的判断方法。

1
2
3
4
5
6
QString file("sample.jpg");
if (file.contains(".jpg") ||
file.contains(".bmp") ||
file.contains(".png")) {
qDebug()<<"这是图片。";
}

  使用Qt接口识别的方法(推荐) :
QMimeType类描述由MIME类型字符串表示的文件或数据类型。

1
2
3
4
5
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile("sample.bmp");
if (mime.name().startsWith("image/")) {
qDebug()<<"这是图片。";
}

一些MIME类型常用对照表

类型 描述 示例
text 普通文本 text/plain,
text/html,
text/css,
text/javascript
image 图像文件(包含动态gif) image/gif,
image/png,
image/jpeg,
image/bmp,
image/webp
audio 音频文件 audio/wav,
audio/mpeg,
audio/midi,
audio/webm,
audio/ogg
video 视频文件 video/mp4,
video/x-flv,
video/webm,
video/ogg
application 二进制数据 application/xml,
application/pdf

兼容Qt4/Qt5版本Qml控件Calendar

发表于 2019-08-04

通过点击日历控件区域,选择日期的Qml组件。

Calendar 备注
导入方法 文件导入
兼容性 QtQuick 1.x与QtQuick 2.x
继承 GridView

插图

阅读全文 »

C/C++黑魔法-匿名数组

发表于 2019-08-03

匿名数组是什么?有什么用?怎么用?一探究竟来自内心深处的敲问!

1.是什么?

  • 匿名数组顾名思义是隐藏(没有)名字的数组。

常规的整型数组:

1
int array[] = {1, 2, 3};

它等价于以下的匿名数组:

1
(int[]){1, 2, 3}

2.有什么用?

  • 匿名数组可以直接当作参数传递,可以不使用临时变量存储。

如:

1
2
3
4
int sum(int array[3])
{
return array[0] + array[1] + array[2];
}

使用常规数组传递参数:

1
2
int array[] = {1, 2, 3};
int result = sum(array);

使用匿名数组传递参数:

1
int result = sum((int[]){1, 2, 3});

3.怎么用?

  • 匿名数组和常规数组一样的语法,只是数组名字被省略了。
  • 上面的array数组的类型是int [],而匿名数组的类型也是int []。
  • 匿名数组的初始化使用{...}和array数组初始化一样。
  • 取匿名数组的下标:
    1
    2
    3
    (int []){1, 2, 3}[0] == 1
    (int []){1, 2, 3}[1] == 2
    (int []){1, 2, 3}[2] == 3

注意

  • C99语法支持匿名数组。
1…101112…32
Qt君

Qt君

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