Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

神烦朝堂悄悄话

发表于 2019-06-04

技术原来很简单,一个早朝故事让你了解编程思维,快来看看C语言国王干了些什么。

  一天,C语言国王正在上早朝,还在苦恼南部葡萄园被上游水库(内存溢出)水淹的事情,正发愁秋天没有做葡萄酒的原料了,于是想让贵族大臣们作出解决的办法。但国王抬头一看,下面都在交头接耳,有说有笑的,国王很是看不惯,如果经常这样,我还怎么做国王了!

  一心想我还惦记着我的葡萄酒啊。你们赶紧想办法!国王愤怒地说了几句,还是有大臣在下面说悄悄话,特别是那个贵族老头。其中函数大臣对运算符老头说,准备扩充自己的领土(职能),由原来的种葡萄增加到种小麦。悄悄话被国王听到更是心里发痒,我的葡萄酒都快要没有着落了,你们还想着种小麦!于是被气得下朝了。
神烦朝堂悄悄话1
  女王看到国王满脸通红,问:国王陛下为何满脸不满?
  国王说:女王啊,虽然你不问朝政,但你掌握后宫繁琐事。应该也有很多主意,你帮我想想。上朝时大臣们老是在下面议论纷纷,却都没有好好找出治理(修复内存溢出)我那个被洪水淹没葡萄园的方法,我还要在秋天喝上新鲜的葡萄酒,你说怎么办呢?

  女王灵机一动:陛下不如增加一条上朝不能说’悄悄话’的规则(标准)?国王若有所思地说,增加标准怕是贵族大臣都有意见(会限制用户思维)。怎么会限制用户思维呢?女王有些不懂。国王说,如果规则过多,贵族大臣们会表达有所顾忌,怕是触发限制,不再说真话。女王再想想办法。

  听闻上个月我们extern关键词使节从东方帝国回来,得到了一个有用的情报。国王立刻命令堆栈士兵传使节回来当面汇报。使节说,东方帝国满地都是黄金。国王心里只惦记着葡萄酒,对黄金没兴趣。问,还有吗?!它们上朝时就没有什么特别的?一心想着解决问题的国王也想知道东方帝国是如何处理大臣在朝上说悄悄话的。使节看到国王很是认真,就说上朝的时候,他们头上都戴着一顶两边很长的帽子(长翅帽)。
神烦朝堂悄悄话2
  国王有些不解地问,有多长?具体多长没注意,但印象中是我一转身就将旁边一片的人都扫倒了,使节如是说。国王听到,这个赵King(赵匡胤)真的很有趣。于是立刻命令在旁的头文件内务大臣,我也要弄这种长帽子,先弄种两米长的长翅帽!赶紧去做,明天给那些贵族大臣们戴!国王想到了解决方法,心里暗喜。

  国王一大早起来就想,你们这些贵族老头,今天我要治好你们说悄悄话的毛病!运算符贵族老头和函数大臣一起踏进大堂,运算符老头对函数老弟说:你昨晚的葡萄酒很好喝,老夫喝得很尽兴,希望你能给我一点… 话还没说到一半,国王走了出来,对着众下说,我为你们准备了东方帝国新潮的帽子,今后你们就戴着这个上朝。旁边的运算符老头一脸不满地戴上两米宽的帽子,心想,小子你等着!

  都戴上两米长的长翅帽后,函数大臣刚要转身问旁边的运算符老头刚才没听清楚的话,还没有转一半就将结构体将军和预编译将军一等人扫倒了。
神烦朝堂悄悄话3
  国王一看情况心里窃喜,机会来了。先拿函数大臣出气!于是罚了函数大臣交出半年的葡萄酒存量。国王的葡萄酒终于有着落了。
  自此之后,众贵族大臣们都不敢再说悄悄话了。


  • 文章首发于微信公众号:Qt君
  • 图片来源于网络

解决QFile找不到路径问题

发表于 2019-06-03

使用QFile报出”系统找不到指定的路径”错误。虽然QFile能够创建不存在的文件,但是它就是不会自动创建不存在的目录。

1.解决方法

1.1 使用QDir::mkdir创建目录

  • 这里需要注意的是它只能创建一个子目录,如果路径存在多个不存在目录则会创建失败。

    1.2 使用QDir::mkpath创建目录

  • 这个接口功能更强大,QDir::mkpath能创建该目录所需的所有父目录。它解决QDir::mkdir只能创建一个子目录的情况。

2.关于QFile自动创建文件的Flag

Flag 解释
QIODevice::WriteOnly 只写模式
QIODevice::ReadWrite 读写模式
QIODevice::Append 追加模式
QIODevice::NewOnly 文件已存在则失败(5.11版本引入)
  • 如需屏蔽自动创建文件操作则需要这样做:
    QIODevice::ExistingOnly(文件不存在则失败5.11版本引入);
    或先判断文件是否存在,不存在则不进行文件打开操作。

Qt快捷打包程序方法

发表于 2019-06-02

介绍两种方式打包程序运行库方式。

1.命令方式

  • 不使用QML组件打包:

    1
    windeployqt xxx.exe
  • 使用QML组件打包:

    1
    windeployqt xxx.exe --qmldir qmlPath
  • 注意: 请使用Qt提供的控制台操作。如:
    windeployqt_console

2.可视界面打包方式

  • 源码地址:

    1
    https://github.com/aeagean/DeployQt
  • 运行包下载地址:

    1
    https://github.com/aeagean/DeployQt/releases/download/V1.0/Qt.V1.0.exe
  • 演示示例:
    Qt程序打包工具

一些Qt第三方语言绑定库

发表于 2019-05-31

Qt API是基于C++实现的,并且提供了额外的特性来简化跨平台开发。整理了一些第三方语言绑定库有Python, Go, Node.js等语言。但是只有Python(PySide2)语言绑定库是由Qt官方维护。快来看看有没有你熟悉的语言吧。

1.Qt官方语言绑定库

序号 语言绑定库
1 PySide2(官方维护)
  • 介绍:使用Qt为Python创建用户界面。Qt for Python是一个项目,它提供了一组官方的Python绑定(PySide2),这些绑定将增强您的Python应用程序。PySide2模块的第一个官方版本现在已经发布了!目前最新支持Qt 5.12版本于2018年12月正式发布。
  • 地址:
    1
    https://www.qt.io/qt-for-python

2.第三方语言绑定库

序号 语言绑定库
1 PyQt
2 Go
3 Node.js
4 C#/Mono/.Net
5 D
6 Ring
7 Rust
8 Crystal
9 Haskell
10 Julia
11 OCaml
12 nelson

2.1 Qt for Python (PyQt)

  • 介绍:PyQt是一组Python v2和v3绑定,用于Qt公司的Qt应用程序框架,运行在Qt支持的所有平台上,包括Windows、OS X、Linux、iOS和Android。PyQt5支持Qt v5。PyQt4支持Qt v4,并将构建Qt v5。绑定是作为一组Python模块实现的,包含1000多个类。
  • 地址:
    1
    http://www.riverbankcomputing.com/news

2.2 Qt for Go (qt)

  • 介绍:Qt绑定用于Go (Golang),支持Windows / macOS / Linux / Android / iOS / Sailfish OS / Raspberry Pi / AsteroidOS / Ubuntu Touch / JavaScript / WebAssembly
  • 地址:
    1
    https://github.com/therecipe/qt

2.3 Qt Quick for Node.js (Brig)

  • 介绍:一个用于Node的用户界面工具包。它是基于Qt进行渲染的。这个项目可以用来加载和播放QML文件,使它有可能有一个简单的方式来沟通QML和Node.js之间的桌面应用程序。
  • 地址:
    1
    https://github.com/BrigJS/brig

2.4.1 Qt for C#/Mono/.Net (QtSharp)

  • 介绍:这个项目目的是创建Mono/.NET库封装Qt,从而通过C#来使用它。它基于优秀的CppSharp。
  • 注意:QtSharp只对Qt for MinGW和Qt的内置MinGW设置进行了测试。
  • 地址:
    1
    https://gitlab.com/ddobrev/QtSharp

2.4.2 Qt for C#/Mono/.Net (Qml.Net)

  • 介绍:使用Qml在.Net中构建跨平台的桌面应用程序。
  • 地址:
    1
    https://github.com/qmlnet/qmlnet

2.5 Qt for D (QtE5)

  • 介绍:QtE5是基于qt的库,提供了从D和c++轻松访问Qt-5的功能。它使用动态Qt5加载和一组预定义的槽,允许您不使用元编译程序。要编译和执行一个应用程序,只需要Qt中的QtE5和一些DLL/SO就足够了,不需要安装Qt。
  • 地址:
    1
    https://github.com/MGWL/QtE5

2.6 Qt for Ring (RingQt)

  • 介绍:使用RingQt进行桌面和移动开发。
  • 地址:
    1
    http://ring-lang.sourceforge.net/doc/qt.html

2.7.1 Qt for Rust (Rust-Qt)

  • 介绍:用于Rust语言的Qt绑定库。
  • 地址:
    1
    https://github.com/rust-qt

2.7.2 Qt Quick for Rust (qml-rust)

  • 介绍:Qt Quick的Rust绑定库。QML库的绑定基于DOtherSide C绑定,与其他基于该库的绑定基本兼容。
  • 注意:缺少一些次要的特性,并且有相当多的bug。
  • 地址:
    1
    https://github.com/White-Oak/qml-rust

2.7.3 Qt Quick for Rust (qmlrs)

  • 介绍:qmlrs允许使用来自Rust的Qml/QtQuick代码Rust代码可以使用加载的Qml脚本创建QtQuick引擎(QQmlApplicationEngine)Qml代码可以调用Rust函数。
  • 注意:有一定的局限性。该库安全性不能保证。
  • 地址:
    1
    https://github.com/flanfly/qmlrs

2.8 Qt for Crystal (qt5.cr)

  • 介绍:基于Bindgen的Crystal的Qt5绑定。
  • 注意:可用的Qt版本: Qt 5.5到Qt 5.10。
  • 地址:
    1
    https://github.com/Papierkorb/qt5.cr

2.9.1 Qt for Haskell (qtHaskell)

  • 介绍:qtHaskell是Trolltech ASA为Qt小部件库提供的一组Haskell绑定。Haskell程序员现在可以访问Qt信号和槽接口逻辑,使用Qt Designer设计接口和Qt ECMA/Javascript引擎编写脚本化应用程序。
  • 地址:
    1
    http://www.isptech.co.uk/qtHaskell/index.html

2.9.2 Qt for Haskell (Qtah)

  • 介绍:Qtah项目是一组用于Haskell的Qt绑定,提供了一个成熟GUI工具包的传统命令式接口。
  • 地址:
    1
    https://gitlab.com/khumba/qtah

2.9.3 Qt Quick for Haskell (HsQML)

  • 介绍:HsQML是一个与Qt Quick的Haskell绑定的库。HsQML允许您将用QML编写的前端设计与用Haskell编写的后端逻辑绑定在一起,从而使用两者的优势创建完整的应用程序。
  • 地址:
    1
    https://www.gekkou.co.uk/software/hsqml/

2.10 Qt for Julia (QML.jl)

  • 介绍:为Julia程序构建Qt5 QML接口。
  • 地址:
    1
    https://github.com/barche/QML.jl

2.11 Qt Quick for OCaml (lablqml)

  • 介绍:QML绑定到OCaml。
  • 注意:使用与Qt 5.3版本以上。
  • 地址:
    1
    https://github.com/Kakadu/lablqml

2.12 QML for Nelson (nelson)

  • 介绍:Nelson是一种数组编程语言,使用现代C/ c++库和其他最先进的数字库为工程和科学应用程序提供了强大的开放计算环境。QML引擎使nelson程序能够使用Qt的QML框架显示和操作图形化内容。
  • 地址:
    1
    https://github.com/Nelson-numerical-software/nelson

版本号定义知多点

发表于 2019-05-30

简短介绍软件版本号的一般定义原则和一些相关知识。

1.格式

  • 主版本号.次版本号.修订号
    例: 1.0.0

2.递增规则

  • 主版本号:当你做了不兼容的 API 修改。
  • 次版本号:当你做了向下兼容的功能性新增。
  • 修订号:当你做了向下兼容的问题修正。

3.先行版本号

  • 先行版本号可以加到”主版本号.次版本号.修订号”的后面,作为延伸。
  • 先行版本号可以被标注在修订号之后,先加上一个连接号再加上一连串以句点分隔的标识符来修饰。被标上先行版本号则表示这个版本并非稳定而且可能无法满足预期的兼容性需求。

4.一些版本号类型

  • X 是主版本号、Y 是次版本号、而 Z 为修订号、x为先行主版本号(非必须);
版本类型 表达方式 含义
正式版 正式版 稳定正式版本
发布候选版 X.Y.Z-rc.x 公测版本基础上的修正版本
beta测试版 X.Y.Z-beta.x 公测版本,
针对所有用户公开的测试版本
alpha测试版 X.Y.Z-alpha.x 内测版本,
用于开发团队或有限用户体验测试版本

5.参考内容:

1
https://semver.org/lang/zh-CN/

Qml变量名为什么不能大写开头?

发表于 2019-05-29

大写开头一般都为对象如Item,Rectangle。而小写或下划线开头的则是变量名字或对象实例。如何使用大写开头的变量则会被解释器认为是对象,从而发生错误。


  • 对象大写开头
    例: Item对象
    1
    2
    Item {
    }

  • 变量下划线,小写开头
    例: item对象实例,isEnable变量名字
    1
    2
    3
    4
    Item {
    id: item
    property bool isEnable: true
    }

关于字符串输出的一些探讨

发表于 2019-05-29

对使用STR(...) #__VA_ARGS__宏输出的字符串的探讨,别有一番风味。

1. 使用以下宏的对照结果

1
#define STR(...) #__VA_ARGS__

1.1 对照1

  • 分析:左括号(与右括号)空格被忽略。
序号 代码 输出结果
1 STR(1,2,3) "1,2,3"
2 STR(1, 2, 3) "1, 2, 3"
3 STR(1 , 2 , 3) "1 , 2 , 3"
4 STR( 1 , 2 , 3 ) "1 , 2 , 3"

1.2 对照2

  • 分析: 单个参数至多保留一个空格。

    1
    STR((    1   ,    2       ,             3   ))
  • 输出:

    1
    "( 1 , 2 , 3 )"

1.3 对照3

  • 分析:单个参数代码换行,实际不换行,多个空格变为一个空格。

    1
    2
    3
    STR(1
    2
    3)
  • 输出:

    1
    "1 2 3"

1.4 对照4

  • 分析:\n实际显示的字符会被保留(与1.3成对照组)。

    1
    2
    3
    STR(1\n
    2\n
    3\n)
  • 输出:

    1
    "1\n 2\n 3\n"

1.5 对照5

  • 分析:带双引号会被转义。

    1
    STR(1, "2", '3')
  • 输出:

    1
    "1, \"2\", '3'"

2. 一些语法解释

  • ...当我们无法列出传递的所有参数的类型和数目时用于占位符的作用;
  • #为把参数转换成字符串;
  • __VA_ARGS__为可变参数宏,一些使用场景:
    1
    fprintf(stdout, format, __VA_ARGS__)

3. 最后

  • 在实际很少很少用到它,很多时候了解就可以了;
  • 倒是这一条宏#define STR(...) #__VA_ARGS__可以学习下。

4. 关于

  • 文章首发于微信公众号你才小学生
  • 后续更新于Qtbig哥(qtbig.com)

关于QProcess不能带空格的目录或文件

发表于 2019-05-27

在Window系统下使用QProcess的start单独运行一个程序时。当程序路径存在空格会运行不成功的现象,最诡异的是,有时又可以运行。这到底是为什么呢?本文将以源码实现的角度来分析到底是为何?

1. 问题重现

  • 下列运行Test Demo.exe将会提示”系统找不到指定的文件。”
    1
    2
    QProcess process;
    process.start("C:/Users/Tmp/Test Demo.exe");

2. 解决方案

  • 解决调用程序不能带有空格的问题。

    2.1 使用使用空参数(arguments)的start接口

  • 接口:

    1
    2
    3
    void start(const QString &program, 
    const QStringList &arguments,
    QIODevice::OpenMode mode)
  • 示例:

    1
    2
    QProcess process;
    process.start("C:/Users/Tmp/Test Demo.exe", QStringList());

2.2 配合转义\字符的start接口

  • 接口:

    1
    void start(const QString &command, QIODevice::OpenMode mode)
  • 示例:

    1
    2
    QProcess process;
    process.start("\"C:/Users/Tmp/Test Demo.exe\"");

3. 为什么会这样?

  在问题重现错误例子中使用的start接口为:

1
void start(const QString &command, QIODevice::OpenMode mode)

  从接口(2.1与2.2)的相似度先提出疑问,为什么一个是program一个是command?
查看了QProcess分析得出program与command的区别是,前者不会对空格进行处理,而后者会把命令字符串以空格进行分割。
  假如command为C:/Users/Tmp/Test Demo.exe,实际上command会被分解为C:/Users/Tmp/Test与Demo.exe。这样就会导致C:/Users/Tmp/Test文件找不到的现象。

4. 源码验证疑问

  • QProcess源码先来一波

    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
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    static QStringList parseCombinedArgString(const QString &program)
    {
    QStringList args;
    QString tmp;
    int quoteCount = 0;
    bool inQuote = false;

    // handle quoting. tokens can be surrounded by double quotes
    // "hello world". three consecutive double quotes represent
    // the quote character itself.
    for (int i = 0; i < program.size(); ++i) {
    if (program.at(i) == QLatin1Char('"')) {
    ++quoteCount;
    if (quoteCount == 3) {
    // third consecutive quote
    quoteCount = 0;
    tmp += program.at(i);
    }
    continue;
    }
    if (quoteCount) {
    if (quoteCount == 1)
    inQuote = !inQuote;
    quoteCount = 0;
    }
    if (!inQuote && program.at(i).isSpace()) {
    if (!tmp.isEmpty()) {
    args += tmp;
    tmp.clear();
    }
    } else {
    tmp += program.at(i);
    }
    }
    if (!tmp.isEmpty())
    args += tmp;

    return args;
    }

    /*!
    \overload

    Starts the command \a command in a new process.
    The OpenMode is set to \a mode.

    \a command is a single string of text containing both the program name
    and its arguments. The arguments are separated by one or more spaces.
    For example:

    \snippet code/src_corelib_io_qprocess.cpp 5

    Arguments containing spaces must be quoted to be correctly supplied to
    the new process. For example:

    \snippet code/src_corelib_io_qprocess.cpp 6

    Literal quotes in the \a command string are represented by triple quotes.
    For example:

    \snippet code/src_corelib_io_qprocess.cpp 7

    After the \a command string has been split and unquoted, this function
    behaves like the overload which takes the arguments as a string list.

    You can disable this overload by defining \c
    QT_NO_PROCESS_COMBINED_ARGUMENT_START when you compile your applications.
    This can be useful if you want to ensure that you are not splitting arguments
    unintentionally, for example. In virtually all cases, using the other overload
    is the preferred method.

    On operating systems where the system API for passing command line
    arguments to a subprocess natively uses a single string (Windows), one can
    conceive command lines which cannot be passed via QProcess's portable
    list-based API. In these rare cases you need to use setProgram() and
    setNativeArguments() instead of this function.

    */
    #if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START)
    void QProcess::start(const QString &command, OpenMode mode)
    {
    QStringList args = parseCombinedArgString(command);
    if (args.isEmpty()) {
    Q_D(QProcess);
    d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
    return;
    }

    const QString prog = args.takeFirst();

    start(prog, args, mode);
    }
    #endif
  • 从上面源码可以看到start(const QString &command, OpenMode mode)接口内部使用到了parseCombinedArgString接口,而这一接口作用是检查字符串以可空格分解参数。

  • 不想命令行被以空格为分解,则不要使用该接口。

5. 怎么避免混用这两个相似的start接口?

  • 在项目(.pro)文件添加以屏蔽start(const QString &command, OpenMode mode)接口的使用。
  • 使用setProgram()和setNativeArguments()也能设置命令与参数。
    1
    DEFINES += QT_NO_PROCESS_COMBINED_ARGUMENT_START

6. 关于更新

  • 文章首发于微信公众号你才小学生
  • 后续更新于Qtbig哥(qtbig.com)

发布Qt程序打包工具

发表于 2019-05-26

由于Qt软件提供的windeployqt采用命令行操作,打包程序起来相对繁琐。而现有大多数的打包工具又不能针对Qt而打包,往往是一些库打包不成功,又或者操作繁琐。如果有一个可视化的傻瓜式的打包工具就好了。也就是这一原因,决定写这个基于Windows系统的可视化Qt打包程序,并开源其代码供大家一起学习进步。

Qt程序打包工具

1. 适用范围

  • Window系统;
  • Qt5.0版本以上编译的程序。

2. 使用方法

  1. 将需要打包的程序拖拽到打包工具中;
  2. 选择该程序编译时的Qt版本和编译器版本;
  3. 点击生成;
  4. 最后测试。

3. 注意

  • 不能打包引入第三方库,需要自己复制到程序运行目录下。

4. 下载使用

  • 最新源代码下载地址

    1
    https://github.com/aeagean/DeployQt/archive/master.zip
  • V1.0源码包下载地址

    1
    https://github.com/aeagean/DeployQt/archive/V1.0.zip
  • V1.0运行文件下载地址

    1
    https://github.com/aeagean/DeployQt/releases/download/V1.0/Qt.V1.0.exe

5. 关于更新

  • 文章首发于微信公众号你才小学生
  • 后续更新于Qtbig哥(qtbig.com)

使用QDesktopServices打开资源文件

发表于 2019-05-25

使用QDesktopServices打开文件目录或网络连接。

打开本地文件或目录

  • 方式1

    1
    QDesktopServices::openUrl(QUrl::fromLocalFile("C:\\Users\\User\\Documents"));
  • 方式2

    1
    QDesktopServices::openUrl(QUrl::fromLocalFile("C:/Users/User/Documents"));
  • 方式3

    1
    QDesktopServices::openUrl(QUrl::fromLocalFile("file:///C:/Users/User/Documents"));

打开网址

1
QDesktopServices::openUrl(QUrl("http://www.qtbig.com/about/"));
1…171819…32
Qt君

Qt君

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