Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

QString的indexOf匹配问题

发表于 2019-06-25

介绍使用indexOf存在匹配字符(串)却匹配不到的问题。

问题重现

  先看例子:

1
2
QString string("hello\0world!");
qDebug()<<string.indexOf("world"); // 打印-1

  由上面例子我们可以看出,indexOf只匹配’\0’前的内容。’\0’是一个空字符常量,它表示一个字符串的结束。

问题分析

  问题出在构造字符串中,由于hello后面跟着’\0’,导致string构造的是hello的内容。

Qt单元测试框架快速上手

发表于 2019-06-25

本文介绍Qt的单元测试框架是什么,有什么用和怎么快速使用它。

1.是什么?

  Qt单元测试框架除了提供单元测试框架的基本功能外还提供了针对GUI测试的扩展功能。一般单元测试意义上是指对软件中的最小可测试单元进行检查和验证,其中最小测试单元可以为某个功能点,某个类,某个函数,甚至是某个行为等等。

2.有什么用?

  • 加快开发效率;
  • 提高程序质量。

3.怎么使用?(图解)

  1. 选择其他项目->Auto Test Project。
    插图

  2. 输入项目名与选择项目目录。
    插图

3.选择一个单元测试的类名(这里是AutoTest)

  • Requires QApplication选项为程序添加QApplication类;
  • Generate initialization and cleanup code选项为添加初始化与清除代码(函数)。
    插图

4.选择编译环境。
插图

5.最后创建完成。
插图

6.项目目录
插图

4.使用技巧

  以AutoTest测试类为例(文末源码),自动执行带有private slots标记的函数,并会顺序执行。

  • initTestCase是默认第一执行函数(系统自带),用于初始化一些数据和行为;
  • cleanupTestCase是默认最后执行函数(系统自带),用于清理资源和重置状态的操作。
    1
    2
    3
    4
    5
    private slots:
    void initTestCase(); /* 可选 */
    void test_case1();
    void test_case2();
    void cleanupTestCase(); /* 可选 */

  测试工具(测试验证函数)

  • 为验证被测试函数的结果,需要使用QTest提供的测试函数。
验证函数 用途
QVERIFY(bool) 验证参数是否为真
QCOMPARE(actual, expected) 验证实际参数是否跟期望值一致
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    void AutoTest::test_case1()
    {
    QString name("AutoTest");
    bool isEnable = true;
    QVERIFY(isEnable);
    QCOMPARE(name, QString("AutoTest"));
    }

5.附录

  • AutoTest.pro

    1
    2
    3
    4
    5
    6
    7
    8
    9
    QT += testlib
    QT -= gui

    CONFIG += qt console warn_on depend_includepath testcase
    CONFIG -= app_bundle

    TEMPLATE = app

    SOURCES += tst_autotest.cpp
  • tst_autotest.cpp

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    #include <QtTest>

    // add necessary includes here

    class AutoTest : public QObject
    {
    Q_OBJECT

    public:
    AutoTest();
    ~AutoTest();

    private slots:
    void initTestCase();
    void test_case1();
    void test_case2();
    void cleanupTestCase();
    };

    AutoTest::AutoTest()
    {

    }

    AutoTest::~AutoTest()
    {

    }

    void AutoTest::initTestCase()
    {

    }

    void AutoTest::test_case1()
    {
    QString name("AutoTest");
    bool isEnable = true;
    QVERIFY(isEnable);
    QCOMPARE(name, QString("AutoTest"));
    }

    void AutoTest::test_case2()
    {

    }

    void AutoTest::cleanupTestCase()
    {

    }

    QTEST_APPLESS_MAIN(AutoTest)

    #include "tst_autotest.moc"
  • 输出信息

    1
    2
    3
    4
    5
    6
    7
    Config: Using QtTest library 5.12.2, Qt 5.12.2 (x86_64-little_endian-llp64 shared (dynamic) debug build; by GCC 7.3.0)
    PASS : AutoTest::initTestCase()
    PASS : AutoTest::test_case1()
    PASS : AutoTest::test_case2()
    PASS : AutoTest::cleanupTestCase()
    Totals: 4 passed, 0 failed, 0 skipped, 0 blacklisted, 2ms
    ********* Finished testing of AutoTest *********

Qml好用的default附加属性

发表于 2019-06-23

Qml存在一个神秘附加属性(default)却是很少用,少用却是很好用。看看我这是怎么用的吧。

1.default附加属性

  • 组件内部({}内)仅此一个default标记。
  • 被deault标记的属性可以使用外部对象。

2.示例1

  MyText.qml组件内部引用外部对象的两种方法。

1
2
3
4
5
6
import QtQuick 2.0

Text {
default property variant textObject
text: textObject.text
}

  方法一:

  • textObject值可以在MyText对象定义中赋值。
  • MyText的Text控件被引用到textObject中使用。
    1
    2
    3
    MyText {
    Text { text: "xxxxx" } // 默认传递给textObject值。
    }

  方法二:

  • 上面操作等同于:
    1
    2
    3
    MyLabel {
    textObject: Text { text: "xxxxx" } // 等同于默认传递给textObject值。
    }

3.例子2

  看似很没用的属性却说有用,还说好用。第一个例子看起来和常规做法差不多。那么我们看看第二个例子使用起来是如何好用的。
  Group.qml组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
import QtQuick 2.0

FocusScope {
property alias title: title.text
default property alias items: colume.children

Text { id: title }

Column {
id: colume
anchors.top: title.bottom
}
}

  Group的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
Group {
title: "title"

Rectangle {
width: 100; height: 50;
color: "red"
}

Rectangle {
width: 100; height: 50;
color: "lightblue"
}
}

  如果不使用该特性则需要这样做:
  如需要多个地方使用则需要重复操作,管理不方便,且理解不直观。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Column {
Text {
text: "title"
}

Column {
Rectangle {
width: 100; height: 50;
color: "red"
}

Rectangle {
width: 100; height: 50;
color: "lightblue"
}
}
}

  效果:
插图

4.最后

  从上面例子可以看到Group组件具备Column控件的布局功能,并扩展出类似于Group Box控件的功能。原因在于colume.children引用了Group的子控件触发自动布局。
  对于上面例子我们还可以内部操控items对象列表来操作Group上的子控件属性,如item[0].visible = false来隐藏红色矩形控件。
  这样做我们就可以增强组件的功能,降低代码量,特别是那些具备标题栏或某些附属栏的组合框。


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

破除匪夷所思bugs,从修正编译警告开始

发表于 2019-06-22

交付软件给客户却是很多问题,一些问题解决就可以了。但有些问题却是一时出现,一时不出现,十分令人恼火,程序猿是超人也难以应付。本文以编译警告为引入点述说在开发过程中的匪夷所思的问题。引以为鉴,重视警告的影响。

1.未引用形参

1
2
warning: unused variable 'value'.
警告:未使用变量"value"

  致命行为:

  • 用错变量导致程序得不到正确结果。

    1
    2
    3
    4
    double sum(double a, double b)
    {
    return a;
    }
  • 变量未使用造成内存泄漏。

    1
    2
    3
    ...
    Car car = new Car();
    ...

  建议:

  • 避免这种行为,但这种情况下大多数出现在作为函数参数。但你要明确的是尽管作为扩展(以后使用)用的函数参数,是否应该考虑下本身设计的问题。

2.可能丢失数据

1
2
warning: implicit conversion turns floating-point number into integer: 'double' to 'int'.
警告:隐式转换将浮点数转换为整数:"double"到"int"。

  致命行为:

  • 丢失精度,类似于蝴蝶效应,小小的精度却会引起巨大的误差。
  • 整型转换枚举导致枚举变量成不确定值。
    1
    2
    enum Fruits { Apple, Orange, Banana};
    Fruits fruits = (Fruits)5; // fruits成不确定值,值取决于编译器。

  建议:

  • 强制转换导致丢失数据,应该避免此行为。
  • 但有些情况下却不会,例如整型转换浮点型,枚举转整型。它们都是从小范围转换到大范围。

3.初始化变量顺序不正确

1
2
warning: field 'j' will be initialized after field 'i'.
警告:字段"j"将在字段"i"之后初始化。

  致命行为:

  • 导致变量值偏离。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Car
    {
    public:
    Car () : j(i + 2), i(1) // 由于j先于i初始化,导致j变量的预期结果却不是3。
    {
    }

    private:
    int i;
    int j;
    };

  建议:

  • 注意:该行为多出现于类和结构体(C++)的构造函数中。
  • 变量之间存在依赖关系容易造成难以想象的bug,就好比怎么有时运行可以,有时却不可以的问题。

4.if语句有空语句

1
2
warning: if statement has empty body.
警告:if语句有语句。

  致命行为:

  • 有时运行正常,有时运行异常(非常令人恼火的bug)。
    1
    2
    if (enable); // 由于";"语句的存在导致value的值一直不会刷新。
    value = sum(i, j);

  建议:

  • 必须修正!

5.可能除0

1
2
warning: division by zero is undefined.
警告:未定义被零除。

  致命行为:

  • 导致程序异常退出。
    1
    value = i / j; // 由于j变量可能为0值,严重会导致程序异常退出。

  建议:

  • 先判断变量是否为不为0,再做运算。

6.变量使用前未初始化

1
2
warning: variable 'value' is uninitialized when used here.
警告:变量"value"在这里使用时未初始化。

  致命行为:

  • 过于相信直觉,以为value默认为0。导致难以想象的bug。
    1
    2
    3
    int value;
    if (value == 0) // 由于变量未确定初始值,则值不确定会导致判断有时会不进入。
    enable = true;

  建议:

  • 养成给变量初始化的好习惯。

7.使用=作为比较

1
2
3
4
warning: using the result of an assignment as a condition without parentheses.
警告:将赋值结果用作不带括号的条件。
use '==' to turn this assignment into an equality comparison.
使用'=='将该赋值转换为相等比较

  致命行为:

  • 唔使用导致判断一直生效或失效的行为。
    1
    2
    3
    4
    5
    if (i = 1) // 一直生效
    enable = true;

    if (i = 0) // 一直失效
    enable = true;

最后

  • 这些编译警告只是冰山一角,有些能正常运行,有些却是致命错误。引以为鉴!
  • 如读者也有些值得注意的警告可以在公众号留言分享给大家。

Qt 5.13版本正式发布(带下载链接)

发表于 2019-06-20

摘录并翻译自Qt官网内容。快来看看新版本更新了些什么东西吧。

插图
  今天(2019-06-19),我们发布了 Qt 5.13,我为每个人都投入的所有工作感到自豪。与往常一样,我们的版本带有新功能,更新,错误修复和改进。对于Qt 5.13,我们也一直专注于我们的工具,使得设计,开发和部署Qt的软件对设计人员和开发人员都更有效。让我们来看看Qt 5.13的一些亮点以及工具方面的一些更新。

1.Qt for WebAssembly

  Qt for WebAssembly允许您为Web浏览器构建Qt应用程序,现在完全支持。WebAssembly的Qt使用Emscripten为Web服务器编译Qt应用程序,允许您在任何支持WebAssembly的浏览器中运行本机应用程序,而无需客户端安装。Qt正在为WebAssembly设置C++开发的步伐,Google最近使用Qt作为如何在Google I/O ‘19活动中在浏览器中运行C ++应用程序的示例。

  • 演示示例:
    1
    https://www.qt.io/qt-examples-for-webassembly

2.Qt GUI

  Qt GUI总结了我们用于窗口系统集成,事件处理,OpenGL和Open GLES集成,2D图形,基本成像,字体和文本的类。

3.Qt QML

  Qt QML模块为使用QML语言开发多变的用户界面提供了一个框架。我们改进了对C++中声明的枚举的支持,在编译时对JavaScript的“null”绑定值进行了优化,现在QML在64位窗口上生成函数表,这使得通过JITed函数展开堆栈成为可能。

4.Qt Quick和Qt Quick Controls 2

  用于编写QML应用程序的标准库和用于创建用户界面的UI控件也做了一些更新。我们已经添加了对TableView隐藏行和列的支持,而对于Qt Quick Controls 2,我们添加了SplitView,这是一个水平或垂直布置项目的控件,每个项目之间都有一个可拖动的拆分器。我们还为icon添加了一个缓存属性。

5.Qt WebEngine

  Qt WebEngine将Chromium的Web功能集成到Qt中,其最新版本现在基于Chromium 73。我们通过内部Chromium扩展,应用程序本地客户端证书存储,QML客户端证书支持,Web Notifications API和一个线程安全的页面特定的URL请求拦截器。

6.Qt网络

  Qt Network为使用TCP/IP的编程应用程序提供了一组API,我们为SSL套接字和OCSP stapling支持添加了安全通道支持。 Qt 5.13现在使用OpenSSL 1.1来支持Linux和Android上的SSL连接。

7.Qt多媒体

  提供丰富的QML类型和C ++类来处理多媒体内容。我们还使用flushMode属性在QML VideoOutput中添加了无缝的回放功能,支持用于Windows/MacOS的GStreamer和用于Android的HTTP头和音频角色。

8.Qt KNX

  客户端-KNXnet/IP服务器连接的客户端。该连接可用于向KNX总线发送消息,并控制通常用于构建自动化的KNX设备的功能。在Qt 5.13中,模块接收到一个安全的客户端API。

9.Qt OPC UA

  基于客户端/服务器(C/S)架构的下一代工业4.0应用程序已收到一些更新。主要是,C++ API现在完全受支持,我们添加了QML API和安全客户端C ++ API的技术预览。

10.Qt CoAP(技术预览版)

  Qt CoAP(约束应用协议)是M2M协议的客户端实现,用于物联网的受约束节点和网络。使用在Qt 5.13,该模块已通过UDP获得对数据报TLS(DTLS)的支持。


其他近期更新

1.Qt Creator IDE 4.9

  Qt Creator IDE已收到一些更新,其中包括改进的Clang分析器工具诊断UI,QML解析器更新,ECMAScript 7支持以及Linux上运行的软件的新性能分析插件。

2.Qt Design Studio 1.2

  最新版本的Qt UI设计和开发工具现在可以让您从Sketch(除Photoshop之外)无缝导入设计并将其转换为QML代码。添加对Sketch的支持一直是一个受欢迎的请求,并且是设计师的流行工具,因此这真的使Design Studio更上一层楼,从而实现更顺畅的设计人员到开发人员工作流程。此外,还增加了对Qt Quick Shapes中更复杂渐变的支持,并进行了各种改进和修复。

3.Qt for Python

  自Qt 5.12附带的第一个官方支持的版本以来,Qt for Python已经收到了大量的错误修复和改进。

4.新版Qt安全渲染器

  TÜVNORD证明您可以使用Qt构建功能安全的嵌入式系统。QSR 1.1基于新版ISO 26262:2018系列标准认证,包括Qt安全渲染器代码,设计器和构建工具,交流安全手册,认证工件和全球Qt技术支持。我们最近的更新允许您动态呈现UI元素。

5.Qt Lottie动画技术预览

  工程师和UI设计人员现在可以使用Bodymovin导出格式和新的Qt Lottie渲染器轻松地将Adobe After Effect动画直接嵌入到Qt Quick应用程序中。


  • 原文链接

    1
    https://blog.qt.io/blog/2019/06/19/qt-5-13-released/
  • 下载链接

    1
    http://download.qt.io/archive/qt/5.13/5.13.0/qt-opensource-windows-x86-5.13.0.exe

  • 翻译者:微信公众号(Qt君)

QtCreator技巧-代码折叠/展开

发表于 2019-06-20

代码一多时很难找到重点内容和容易让人心情不好。通过代码折叠功能让代码安安静静地在一角落躺着,岂不是一件美滋滋的事。

折叠/展开方法

1.光标指向对应的代码块操作ctrl + shift + <折叠代码块和ctrl + shift + >展开代码块;
2.edit(编辑)->advanved(高级)->Toggle Fold All(切换折叠所有);
3.在编辑界面点击行号所在的三角形图标可以折叠和展开代码。
插图

折叠/展开范围

  • {}所包含的代码块。
  • /**/所包含的注释。

窗口置顶操作

发表于 2019-06-19

使用setWindowFlags接口设置窗口的WindowStaysOnTopHint属性实现置顶操作。

接口

1
2
Qt::WindowFlags windowFlags() const
void setWindowFlags(Qt::WindowFlags type)

窗口置顶

  • 通知窗口系统该窗口应该位于所有其他窗口之上。注意,在X11上的一些窗口管理器上,您还必须传递Qt::X11BypassWindowManagerHint,以使此标志正确工作。
    1
    setWindowFlags(windowFlags()| Qt::WindowStaysOnTopHint);

窗口置底

  • 通知窗口系统该窗口应该位于所有其他窗口的底部。
    1
    setWindowFlags(windowFlags()| Qt::WindowStaysOnBottomHin);

Qt快速转换路径(斜杠与反斜杠转换)

发表于 2019-06-17

使用Qt编写跨平台软件,在linux与windows系统的路径表达都不尽相同。本文介绍如何快速转换’/‘与’\’路径的方法。

/转\(斜杠转反斜杠)

  • 使用QDir::toNativeSeparators接口
  • 示例:

    1
    2
    QString path = "C:/temp/test.txt";
    path = QDir::toNativeSeparators(path);
  • 输出

    1
    "C:\\temp\\test.txt"

\转/(反斜杠转斜杠)

  • 使用QDir::fromNativeSeparators
  • 示例:

    1
    2
    QString path = "C:\\temp\\test.txt";
    path = QDir::toNativeSeparators(path);
  • 输出

    1
    C:/temp/test.txt

C/C++黑魔法-随处安放的try

发表于 2019-06-16

一般try..catch块语句都用在函数体内,但是也有例外的时候,对于作者这种懒人,写语句能省则省。看看我是怎么操作的吧。

1.”随处安放”在函数体’外’

  • 看到以下代码相信不少人会认为语法错误吧,写少了一对{},实则下面这段函数是没问题的。

    1
    2
    3
    4
    5
    6
    7
    void func()
    try {
    printf("This is a function.");
    }
    catch (...) {

    }
  • 相当于

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void func() 
    {
    try {
    printf("This is a function.");
    }
    catch (...) {

    }
    }

2.为什么会这样,是什么黑魔法导致这样?

  先看看try块的语法:

  • 函数try块是一种函数体的替代语法形式,也是函数定义的一部分。

  一般以下形式表示:

  • catch称为处理块序列(可以是多个)
  • 函数体中的任何语句中抛出的所有异常,将控制转移到处理块序列(catch)中。
    1
    2
    3
    4
    5
    6
    try {
    ...
    }
    catch (...) {
    ...
    }

  解开魔法

  • 根据try块语法,try函数块可以作为函数体的替代。

3.这个有什么用?

  当然有用啦。存在即合理,这魔法当然需要做点什么啦?!

  1. 构造函数成员初始化器列表中捕获异常,主要是构造过程中抛出异常清理构造过程中已经申请的内存,如果不能清空已构造的内存则会导致内存泄漏。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class A
    {
    public:
    A(int count) try : m_count(count) {
    new B();
    ...
    throw;
    }
    catch (...) {
    // 清空构造函数所产生的内存, 如清空new B()申请的内存。
    }

    ~A() try {
    }
    catch (...) {
    }

    private:
    int m_count;
    };
  2. 用在debug调试中,只要定义DEBUG宏即能使用try...catch机制。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void func()
    #ifdef DEBUG
    try
    #endif
    {
    ... // 一些操作
    }
    #ifdef DEBUG
    catch(...) {
    }
    #endif /* DEBUG */

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

关于Qml的Window控件不能使用id进行布局定位的问题

发表于 2019-06-15

解决Qml的Window控件不能使用id进行布局定位的问题。

问题重现

  • 运行后Rectangle并不能按照预想的置于底部行为,而是布局不变(默认布局顶部)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Window {
    id: root
    visible: true
    width: 640
    height: 480

    Rectangle {
    id: rect
    width: 100; height: 100
    anchors.bottom: root.bottom
    color: "red"
    }
    }

分析

  • 先查看Qt官方文档找找线索,既然布局不了就找anchors布局的文档,通过全局搜索文档找到了以下信息。

    1
    2
    Note: You can only anchor an item to siblings or a parent. 
    注意:只能将项目锚定到同级或父级。
  • 由此可以推测Window的rootid所指向的并不是派生于Item(或QQuickItem)的。

  • 通过打印Window的id与parent属性分别为QQuickWindowQmlImpl与QQuickRootItem,可以肯定的是QQuickWindowQmlImpl不是继承于QQuickItem,导致布局不到的问题。
  • 感觉那里不对,又找了下文档,看到以下信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [default] data : list<Object>

    The data property allows you to freely mix visual children, resources and other Windows in a Window.
    If you assign another Window to the data list, the nested window will become "transient for" the outer Window.
    If you assign an Item to the data list, it becomes a child of the Window's contentItem, so that it appears inside the window. The item's parent will be the window's contentItem, which is the root of the Item ownership tree within that Window.
    If you assign any other object type, it is added as a resource.
    It should not generally be necessary to refer to the data property, as it is the default property for Window and thus all child items are automatically assigned to this property.

    data属性允许您在Window中自由混合可视子项,资源和其他Windows。
    如果将另一个窗口分配给数据列表,嵌套窗口将变为"瞬态"外部窗口。
    如果将一个Item分配给数据列表,它将成为Window的contentItem的子项,以便它出现在窗口内。 项目的父项将是窗口的contentItem,它是该窗口中项目所有权树的根。
    如果指定任何其他对象类型,则将其添加为资源。
    通常不需要引用data属性,因为它是Window的默认属性,因此所有子项都会自动分配给此属性。
  • 大概意思是Window窗口的根Item被附加在contentItem上。

解决方法

  • 使用parent或root.contentItem或Window.contentItem替换root作为布局的锚。
1…151617…32
Qt君

Qt君

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