Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

Qt4与Qt5的QUrl兼容性

发表于 2019-08-02

我们使用QUrl装载url请求的时候,往往需要写参数,但是由于Qt4与Qt5的改动导致QUrl接口也会不一样。

1
http://www.example.com?key1=value1&key2=value2

Qt4写法

1
2
3
QUrl url("http://www.example.com");
url.addQueryItem("key1", "value1");
url.addQueryItem("key2", "value2");

Qt5写法

1
2
3
4
5
QUrl url("http://www.example.com");
QUrlQuery urlQuery(url);
urlQuery.addQueryItem("key1", "value1");
urlQuery.addQueryItem("key2", "value2");
url.setQuery(urlQuery);

兼容Qt4/Qt5写法

1
2
3
4
5
6
7
8
9
10
11
    QUrl url("http://www.example.com");
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) // Qt4
url.addQueryItem("key1", "value1");
url.addQueryItem("key2", "value2");
#else
QUrlQuery urlQuery(url);

urlQuery.addQueryItem("key1", "value1");
urlQuery.addQueryItem("key2", "value2");
url.setQuery(urlQuery);
#endif

Qt编译完成后自动执行脚本

发表于 2019-08-01

有时候我们编译程序完成后需要执行某些操作,比如复制执行文件或库文件到指定目录,如果这些都靠手动复制,未免会太繁琐且容易出错。本文介绍使用Qmake工具编译完成后自动执行自定义脚本的方法。

编译完成后执行脚本/命令

  • 使用QMAKE_POST_LINK变量可以指定一个或多个脚本/命令在编译完成(链接)后执行的操作。
  • 比如:
    1
    QMAKE_POST_LINK += cmd_line1 cmd_line2

编译完成前执行脚本/命令

  • 使用QMAKE_PRE_LINK变量可以指定一个或多个脚本/命令在编译完成前(链接前)执行的操作。
  • 比如:
    1
    QMAKE_PRE_LINK += cmd_line1 cmd_line2

完整示例

  • 命令

    1
    2
    3
    4
    5
    BEFORE_LINK_CMD_LINE = echo Hello world!
    QMAKE_PRE_LINK += $$quote($$BEFORE_LINK_CMD_LINE)

    AFTER_LINK_CMD_LINE = echo Build Success!
    QMAKE_POST_LINK += $$quote($$AFTER_LINK_CMD_LINE)
  • Hello world!在程序链接前输出。

  • Build Success!在程序链接(编译完成)后输出。
    1
    2
    3
    4
    5
    6
    g++ -c -pipe -g -std=gnu++0x -Wall -W -D_REENTRANT -fPIC -DQT_QML_DEBUG -DQT_CORE_LIB -I../untitled -I. -I../../Tools/Qt5.6.3/5.6.3/gcc_64/include -I../../Tools/Qt5.6.3/5.6.3/gcc_64/include/QtCore -I. -I../../Tools/Qt5.6.3/5.6.3/gcc_64/mkspecs/linux-g++ -o main.o ../untitled/main.cpp
    echo Hello world!
    Hello world!
    g++ -Wl,-rpath,/home/strong/Tools/Qt5.6.3/5.6.3/gcc_64/lib -o untitled main.o -L/home/Tools/Qt5.6.3/5.6.3/gcc_64/lib -lQt5Core -lpthread
    echo Build Success!
    Build Success!

为Qt程序获取编译日期时间

发表于 2019-07-31

利用DATE与TIME编译宏特性为Qt程序添加编译日期时间。

1
2
3
4
5
6
7
static const QDateTime buildDateTime()
{
QString dateTime;
dateTime += __DATE__;
dateTime += __TIME__;
return QLocale(QLocale::English).toDateTime(dateTime, "MMM dd yyyyhh:mm:ss");
}

另外,下列代码并不能获取编译日期时间,而是获取程序运行当前的日期时间。

1
QDateTime::currentDateTime()

跨平台sleep,msleep,usleep兼容性问题

发表于 2019-07-30

写Linux应用时用到睡眠函数,比如sleep,usleep,但是将应用移植到Windows系统却是编译错误。本文解决Linux与Windows睡眠函数的兼容性问题。

插图

1.宏替换实现

  • 使用Qt的Q_OS_WIN32宏识别系统,读者可以改用其他宏来识别系统。
  • Windows系统的Sleep睡眠函数单位是毫秒。
  • Linux系统的sleep睡眠函数单位是秒。
  • 使用宏扩展出msleep睡眠函数单位是毫秒。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <QCoreApplication>

    #ifdef Q_OS_WIN32
    #include <windows.h>
    #define sleep(sec) Sleep(sec * 1000)
    #define msleep(msec) Sleep(msec)
    #else
    #include <unistd.h>
    #define msleep(msec) usleep(msec * 1000)
    #endif

2.关于Windows下的usleep

  • 在Windows系统下使用微秒睡眠,实际用处不大,一般API调用都几微秒了。
  • 有好过没有,万一有一天可能会用到。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static void usleep(unsigned long usec)
    {
    HANDLE timer;
    LARGE_INTEGER interval;
    interval.QuadPart = -(10 * usec);

    timer = CreateWaitableTimer(NULL, TRUE, NULL);
    SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
    WaitForSingleObject(timer, INFINITE);
    CloseHandle(timer);
    }

3.兼容实现

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
#include <QCoreApplication>

#ifdef Q_OS_WIN32
#include <windows.h>
#define sleep(sec) Sleep(sec * 1000)
#define msleep(msec) Sleep(msec)

static void usleep(unsigned long usec)
{
HANDLE timer;
LARGE_INTEGER interval;
interval.QuadPart = -(10 * usec);

timer = CreateWaitableTimer(NULL, TRUE, NULL);
SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
}
#else
#include <unistd.h>
#define msleep(msec) usleep(msec * 1000)
#endif

int main(int argc, char *argv[])
{
sleep(1);
msleep(100);
usleep(1000);
}

Qt官方示例源码

发表于 2019-07-29

Qt的官方例子很多都是经过历史沉淀,简单易学,都是很好的学习例子,所以Qt君收集一些Qt官方示例的使用方法,供大家一起学习。

1.官方在线示例教程地址

1
https://doc.qt.io/qt-5/qtexamples.html#

插图

2.QtCreator示例

  • 在”欢迎“->”示例“。
    插图

3. Qt自带官方例子

  • 在安装目录下的对应版本的Examples目录下可以找到。
  • 例如:
    1
    C:\Qt\Qt5.12.4\Examples\Qt-5.12.4

插图

4.Qt君整理的官方例子(提取自Qt5.12.4)

  • Github仓库

    1
    https://github.com/aeagean/QtOfficialExamples
  • 下载地址

    1
    https://github.com/aeagean/QtOfficialExamples/archive/master.zip

插图


后续Qt君会不定期更新对Qt官方例子的分析讲解。

轻量级Qt键盘-实现篇

发表于 2019-07-28

介绍该键盘项目的代码实现。

插图

1.布局

采用垂直布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
QHBoxLayout *h1();
QHBoxLayout *h2();
QHBoxLayout *h3();
QHBoxLayout *h4();

QVBoxLayout *layout = new QVBoxLayout();
layout->setSpacing(BUTTON_SPACING_RATIO*height());
layout->addLayout(h1());
layout->addLayout(h2());
layout->addLayout(h3());
layout->addLayout(h4());

mainLayout->addStretch();
mainLayout->addLayout(layout);
mainLayout->addStretch();

2.KeyButton生成

  • 从第一行的键盘布局代码中可以看到,使用for循环创建KeyButton。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    QHBoxLayout *Keyboard::h1()
    {
    QHBoxLayout *h = new QHBoxLayout;
    ...
    for (int i = 0; i < modeListBar1.count(); i++) {
    KeyButton *button = createButton(modeListBar1.at(i));
    h->addWidget(button);
    }

    ...
    }

插图

  • 创建createButton中传递按键的三个状态信息(以第一行为例)。
    1
    2
    3
    4
    5
    6
    7
    KeyButton *Keyboard::createButton(QList<KeyButton::Mode> modes)
    {
    KeyButton *button = new KeyButton(modes, this);
    button->onReponse(this, SLOT(onKeyPressed(const int&, const QString&)));
    button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    return button;
    }

插图

  • 每一行内容分别分为小写状态,大写状态,字符状态。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const QList<Modes> modeListBar1 = {
    {{Qt::Key_Q, "q"}, {Qt::Key_Q, "Q"}, {Qt::Key_1, "1"}},
    {{Qt::Key_W, "w"}, {Qt::Key_W, "W"}, {Qt::Key_2, "2"}},
    {{Qt::Key_E, "e"}, {Qt::Key_E, "E"}, {Qt::Key_3, "3"}},
    {{Qt::Key_R, "r"}, {Qt::Key_R, "R"}, {Qt::Key_4, "4"}},
    {{Qt::Key_T, "t"}, {Qt::Key_T, "T"}, {Qt::Key_5, "5"}},
    {{Qt::Key_Y, "y"}, {Qt::Key_Y, "Y"}, {Qt::Key_6, "6"}},
    {{Qt::Key_U, "u"}, {Qt::Key_U, "U"}, {Qt::Key_7, "7"}},
    {{Qt::Key_I, "i"}, {Qt::Key_I, "I"}, {Qt::Key_8, "8"}},
    {{Qt::Key_O, "o"}, {Qt::Key_O, "O"}, {Qt::Key_9, "9"}},
    {{Qt::Key_P, "p"}, {Qt::Key_P, "P"}, {Qt::Key_0, "0"}},
    };

插图

  • 根据传递的信息默认显示小写状态的内容。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    KeyButton::KeyButton(const QList<KeyButton::Mode> modes, QWidget *parent) :
    QPushButton(parent)
    {
    ...
    if (!modes.isEmpty()) {
    m_preMode = m_mode = m_modes.first();
    setText(m_mode.display);
    }

    connect(this, SIGNAL(pressed()), this, SLOT(onPressed()));
    }

3.按键状态切换

  • 键盘存在三种形态,小写状态,大写状态,字符状态。
  • 一个按键存在三种状态,意味​按键有三种状态切换,当键盘Keyboard类绑定切换状态的按键,进行响应的操作。当键盘Keyboard类绑定切换状态的按键,进行响应的操作。
  • 通过按键的状态值来绑定Keyboard的处理信号(switchCapsLock(),switchSpecialChar())。

    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
    void Keyboard::resizeButton()
    {
    foreach (KeyButton *button, findChildren<KeyButton *>()) {
    ...

    switch (button->mode().key) {
    case Qt::Key_CapsLock:
    ...
    connect(button,
    SIGNAL(pressed()),
    this,
    SLOT(switchCapsLock()),
    Qt::UniqueConnection);
    break;
    case Qt::Key_Mode_switch:
    ...
    connect(button,
    SIGNAL(pressed()),
    this,
    SLOT(switchSpecialChar()),
    Qt::UniqueConnection);
    break;
    default:
    break;
    }
    }

    ...
    }
  • 触发切换大写状态,遍历设置每个按键的switchCapsLock()函数。

    1
    2
    3
    4
    5
    6
    void Keyboard::switchCapsLock()
    {
    QList<KeyButton *> buttons = findChildren<KeyButton *>();
    foreach(KeyButton *button, buttons)
    button->switchCapsLock();
    }
  • KeyButton的switchCapsLock()函数切换按键显示的内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void KeyButton::switchCapsLock()
    {
    if (m_mode.type == SpecialChar)
    return;

    m_preMode = m_mode;
    m_mode = find(m_mode.type == LowerCase ? UpperCase : LowerCase);
    setText(m_mode.display);
    }

4.发送模拟事件到焦点窗口

  • 当创建按键的同时也会绑定AbstractKeyboard的onKeyPressed槽函数。

    1
    2
    KeyButton *button = new KeyButton(modes, this);
    button->onReponse(this, SLOT(onKeyPressed(const int&, const QString&)));
  • 使用QApplication的sendEvent发送按键事件到焦点窗口。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void AbstractKeyboard::onKeyPressed(int key, QString value) 
    {
    QWidget *receiver = QApplication::focusWidget();
    if (!receiver)
    return;

    QKeyEvent keyPress(QEvent::KeyPress, key, Qt::NoModifier, value);
    QKeyEvent keyRelease(QEvent::KeyRelease, key, Qt::NoModifier, value);

    QApplication::sendEvent(receiver, &keyPress);
    QApplication::sendEvent(receiver, &keyRelease);
    }

为什么Unix使用的是tar.gz而很少使用zip或rar格式?

发表于 2019-07-27

我们经常遇到在Windows系统的rar或zip压缩文件到Unix就没有了权限,比如添加文件执行权限需要使用chmod +x 执行文件命令。

为什么?

  • zip或rar格式不能保留Unix的文件权限。
  • 需要保留Unix的文件权限,可以使用tar.gz压缩来保留。

为什么这么长的后缀?

xxx.tar.gz含义:

  • xxx压缩文件名字;
  • tar作用为将文件归档(将多文件合并为一个文件);
  • gz作用为提供对归档文件的压缩功能。
  • 因为Unix中有一个哲学为程序应该只关注一个目标,并尽可能把它做好。

正确解释为:
归档并压缩的xxx文件。

Windows编译libjpeg库

发表于 2019-07-26

Qt君最近在做图像相关的项目,用到了libjpeg库。记录libjpeg编译步骤供大家参考。

1.下载源码(jpegsrc9c.zip)

  • 官网地址:
    1
    http://www.ijg.org/

插图

  • jepgsrc9c.zip源码包下载地址:

    1
    http://www.ijg.org/files/jpegsr9c.zip
  • 如上的下载地址失效可以使用Qt君的github仓库下载:

    1
    https://github.com/aeagean/LibjpegForWindows/blob/master/jpeg-9c/jpegsr9c.zip

2.如何找到编译配置方法?

  下载的源码中有一个编译安装教程文件(install.txt)

  • 从install.txt中摘取的VC++6配置编译方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Microsoft Windows, Microsoft Visual C++ 6 Developer Studio:

    To use:
    1. Open the command prompt, change to the main directory and execute the
    command line
    NMAKE /f makefile.vs setup-vc6
    This will move jconfig.vc to jconfig.h and makefiles to project files.
    (Note that the renaming is critical!)
    2. Open the workspace file jpeg.dsw, build the library project.
    (If you are using Developer Studio more recent than 6.0, you'll
    probably get a message saying that the project files are being updated.)
    3. Open the workspace file apps.dsw, build the application projects.
    4. To perform the self-test, execute the command line
    NMAKE /f makefile.vs test-build
    5. Move the application .exe files from `app`\Release to an
    appropriate location on your path.
  • 从install.txt中摘取的VS2017配置编译方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Microsoft Windows, Visual Studio 2017 (v15):

    To use:
    1. Open the Developer Command Prompt, change to the main directory and
    execute the command line
    NMAKE /f makefile.vs setup-v15
    This will move jconfig.vc to jconfig.h and makefiles to project files.
    (Note that the renaming is critical!)
    2. Open the solution file jpeg.sln, build the library project.
    a) If you are using Visual Studio more recent than
    2017 (v15), you'll probably get a message saying
    that the project files are being updated.
    b) If necessary, open the project properties and
    adapt the Windows Target Platform Version in
    the Configuration Properties, General section;
    we support the latest version at the time of release.
    3. Open the solution file apps.sln, build the application projects.
    4. To perform the self-test, execute the command line
    NMAKE /f makefile.vs test-build
    5. Move the application .exe files from `app`\Release to an
    appropriate location on your path.

3.以编译VS2017版本为例

  由于VC++6的编译方法与VS2017方法基本相同,这里使用VS2017的编译环境编译。

3.1 编译步骤

1. 打开VS2017开发者终端,主要是使用VS2017的开发环境。

插图

2. 进入libjpeg库目录,使用NMAKE命令生成VS2017的项目文件(用于编译libjpeg库)。

  图示:
插图

  命令:

1
NMAKE /f makefile.vs setup-v15

  这一步可能遇到的问题:如果出现以下情况,可能是你重复调用命令生成,导致文件不能重命名,或你修改了里面的一些文件名字。建议重新解压libjpeg库再执行命令生成。
插图

3. 打开libjpeg库目录的jpeg.sln项目文件。

插图

  这一步可能遇到的问题:

1
2
jpeg.vcxproj.filters : warning  : 无法读取筛选器文件“jpeg.vcxproj.filters”。请卸载项目“jpeg.vcxproj”以便对其进行编辑。
jpeg.vcxproj.filters(1,1): 未能加载项目文件。根级别上的数据无效。 第 1 行,位置 1。

  解决方法:

  • 使用记事本打开jpeg.vcxproj删除第1行的第1个位置的乱码字符;
  • 另存为UTF-8格式并覆盖jpeg.vcxproj文件。
  • 相似的问题可以使用同样的方法解决。
    插图

4. 编译

  这一步可能遇到的问题:

  • Windows SDK版本不匹配的问题。
    插图

  解决方法:修改Windows SDK版本:
插图
插图

  • 提示必须定义入口点的问题:
    插图

  解决方法:设置动态库或静态库:
插图

3.2 最后编译成功

插图

4.打包好的库和头文件

插图

  • 仅供学习使用。
  • 32位与64位的release版本静态库。
  • 地址:
    1
    https://github.com/aeagean/LibjpegForWindows

git命令使用笔记2

发表于 2019-07-25

列举使用到的一些git命令。

  • 切换到某个分支
    git checkout 分支名

  • 查看分支
    git branch -a

  • 分支切换并创建
    git checkout -b 分支名 提交ID

  • 删除本地分支
    git branch -d 分支名

  • 删除远程分支
    git push origin –delete 分支名

  • 推送远程tag
    git push origin tag名字

  • 本地删除tag
    git tag -d tag名字

  • git只合并某一个分支的commit

1)只合并一个commit(将分支2的提交id合并到分支1)

1
2
git checkout 分支1
git cherry-pick 分支2提交id

2)合并连续的多个commit到指定的分支上(将分支2的范围commit合并到分支1)

  • 为分支2创建一个临时的最后范围commit的分支

    1
    git checkout -b temp 最后范围commit
  • 将tmp分支最开始范围的commit用rebase合并范围commit

    1
    git rebase --onto 分支1 最开始范围commit

git命令使用笔记1

发表于 2019-07-25

列举使用到的一些git命令。

作用 命令
显示某次提交的修改内容 git show <commit_id>
显示某次提交的某个文件的修改内容 git show <commit_id> <文件>
显示以前每一次提交的修改内容 git log -p <文件>
显示n次前提交的修改内容 git log -p -n <文件>
恢复到某个文件的状态 git checkout <commit_id> <文件>
比较某个文件的两个历史记录 git diff <commit_id1> <commit_id2> <文件>
取消合并操作 git merge --abort
将当前内容暂存到缓存区 git stash
将缓存区内容取出 git stash pop
1…111213…32
Qt君

Qt君

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