Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

C++替代关键词(and,or,not)

发表于 2019-10-21

下列例子用到了C++的关键词and,not,虽然这种做法比较少用,但它可读性比||和!会好很多。

1
2
3
4
5
6
7
8
bool isOk = false;
int i = 1;
if (i < 2 and i > 0)
isOk = true;

if (not isOk) {
printf("OK");
}

替代关键词有哪些?

  可以在iso646.h头文件中找到:

替代关键词 对应符号
and &&
and_eq &=
bitand &
bitor `\ `
compl ~
not !
not_eq !=
or `\ \ `
or_eq `\ =`
xor ^
xor_eq ^=

关于替代关键词

  • 使用and,or这些关键词时可以避免只写一个&或|导致逻辑错误。

    1
    2
    3
    4
    5
    6
    7
    if (x && y) { ... }

    /* 遗留了&可能导致程序意想不到的缺陷 */
    if (x & y) { ... }

    /* 而遗留了and则直接导致编译错误,从而发现错误 */
    if (x and y) { ... }
  • 可读性更好,与阅读大量单词相比,阅读符号并了解它们的含义理解起来要快得多。

  • 在很久以前的计算机键盘中由于没有& | ^等字符,需要使用关键词来标识。
  • 不同的编译器对这些关键词可能不支持。Qt君使用mingw7.3.0编译器可以通过,而使用MSVC2017则编译不通过,需要设置编译器选项/Za以支持替代关键字。
  • 似乎符号表达的方式在使用上更加流行。

更多精彩文章请关注微信公众号:「Qt君」

解决一个触摸屏兼容性问题

发表于 2019-10-21

解决使用win10系统触摸屏触控正常,而在win7系统中却触摸不了的问题。

问题还原

  • 下列代码中win10触摸板能正常工作,但在win7系统中却触摸不了。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* main.cpp */
    QQuickWidget view;
    view.setSource(QUrl("qrc:Main.qml"));
    view.show();

    /* Main.qml */
    Item {
    MouseArea {
    anchors.fill: parent
    onClicked: console.log(">>>>")
    }
    }

问题分析

  通过拦截Qt的事件队列,可以看到win10系统中的触摸事件如下:

1
2
3
4
5
6
7
QQuickMouseArea -> QEvent::TouchBegin
...
QQuickMouseArea -> QEvent::TouchEnd
...
QQuickWidget -> QEvent::MouseButtonPress
QQuickWindow -> QEvent::MouseButtonPress
QQuickMouseArea -> QEvent::MouseButtonPress

  win7中的触摸事件:

1
2
3
4
5
6
QQuickMouseArea -> QEvent::TouchBegin
...
QQuickMouseArea -> QEvent::TouchEnd
...
QQuickWidget -> QEvent::MouseButtonPress
QQuickWindow -> QEvent::MouseButtonPress

  通过触摸事件信息对比win10与win7信息中它们都触发了触摸事件,由于Qt默认将触摸事件定向到鼠标事件,但win7最后却没有触发QEvent::MouseButtonPress导致显示触摸没反应的问题。

问题解决

  • 为QWidget的派生类设置Qt::WA_AcceptTouchEvents属性,如:

    1
    view->setAttribute(Qt::WA_AcceptTouchEvents);
  • 由于QTouchEvent和QMouseEvent事件独立。想要它们合成事件可以设置QCoreApplication的setAttribute的应用标记Qt::AA_SynthesizeTouchForUnhandledMouseEvents和Qt::AA_SynthesizeMouseForUnhandledTouchEvents用于启用或禁用触摸事件到鼠标事件或鼠标事件到触摸事件的自动合成。

  • 其中,Qt::AA_SynthesizeMouseForUnhandledTouchEvents是不接受的所有触摸事件都将转换为鼠标左键事件。默认情况下启用此属性。

Qt官方示例-图表主题

发表于 2019-10-20

示例可以设置图表的系统内置主题。

demo

0x00 主题样式预览

  • Light主题

插图

  • Blue Cerulean主题

插图

  • Dark主题

插图

  • Brow Sand主题

插图

  • Blue NCS主题

插图

  • High Contrast主题

插图

  • Blue Icy主题

插图

  • Qt经典主题

插图

0x01 创建图表

  以面积图为例。

  • 需要创建QChart类作为面积图图表容器。

    1
    2
    QChart *chart = new QChart();
    chart->setTitle("Area chart");
  • 创建QLineSeries与QAreaSeries实例装载数据。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    for (int i(0); i < m_dataTable.count(); i++) {
    QLineSeries *upperSeries = new QLineSeries(chart);
    for (int j(0); j < m_dataTable[i].count(); j++) {
    Data data = m_dataTable[i].at(j);
    if (lowerSeries) {
    const QVector<QPointF>& points = lowerSeries->pointsVector();
    upperSeries->append(QPointF(j, points[i].y() + data.first.y()));
    } else {
    upperSeries->append(QPointF(j, data.first.y()));
    }
    }
    QAreaSeries *area = new QAreaSeries(upperSeries, lowerSeries);
    area->setName(name + QString::number(nameIndex));
    nameIndex++;
    chart->addSeries(area);
    lowerSeries = upperSeries;
    }
  • 设置默认坐标轴和坐标轴范围。

    1
    2
    3
    chart->createDefaultAxes();
    chart->axes(Qt::Horizontal).first()->setRange(0, m_valueCount - 1);
    chart->axes(Qt::Vertical).first()->setRange(0, m_valueMax);
  • 设置坐标轴的标签格式。

    1
    2
    3
    QValueAxis *axisY = qobject_cast<QValueAxis*>(chart->axes(Qt::Vertical).first());
    Q_ASSERT(axisY);
    axisY->setLabelFormat("%.1f ");

0x02 设置主题

  用户可以可以选择系统中的内置主题。然后将此主题应用于布局中的所有图表。

  • 配置组合框中的内置主题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // add items to theme combobox
    m_ui->themeComboBox->addItem("Light", QChart::ChartThemeLight);
    m_ui->themeComboBox->addItem("Blue Cerulean", QChart::ChartThemeBlueCerulean);
    m_ui->themeComboBox->addItem("Dark", QChart::ChartThemeDark);
    m_ui->themeComboBox->addItem("Brown Sand", QChart::ChartThemeBrownSand);
    m_ui->themeComboBox->addItem("Blue NCS", QChart::ChartThemeBlueNcs);
    m_ui->themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
    m_ui->themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
    m_ui->themeComboBox->addItem("Qt", QChart::ChartThemeQt);
  • 设置组合框中的内置主题样式。

    1
    2
    3
    4
    5
    6
    7
    8
    QChart::ChartTheme theme = static_cast<QChart::ChartTheme>(
    m_ui->themeComboBox->itemData(m_ui->themeComboBox->currentIndex()).toInt());
    //![6]
    const auto charts = m_charts;
    if (!m_charts.isEmpty() && m_charts.at(0)->chart()->theme() != theme) {
    for (QChartView *chartView : charts) {
    //![7]
    chartView->chart()->setTheme(theme);

0x03 设置图表动画

  可以设置每个图表上动画类型。

动画演示

  • 组合框动画类型:
  1. 没有动画;
  2. 网格轴动画;
  3. 系列动画;
  4. 或者两者都有。
    1
    2
    3
    4
    m_ui->animatedComboBox->addItem("No Animations", QChart::NoAnimation);
    m_ui->animatedComboBox->addItem("GridAxis Animations", QChart::GridAxisAnimations);
    m_ui->animatedComboBox->addItem("Series Animations", QChart::SeriesAnimations);
    m_ui->animatedComboBox->addItem("All Animations", QChart::AllAnimations);
  • 遍历设置全部图表动画。
    1
    2
    3
    4
    5
    6
    QChart::AnimationOptions options(
    m_ui->animatedComboBox->itemData(m_ui->animatedComboBox->currentIndex()).toInt());
    if (!m_charts.isEmpty() && m_charts.at(0)->chart()->animationOptions() != options) {
    for (QChartView *chartView : charts)
    chartView->chart()->setAnimationOptions(options);
    }

0x04 设置图表额外信息

  显示图表的额外信息在不同侧面。

插图

  • 可以设置不同侧面显示图表信息。

    1
    2
    3
    4
    5
    m_ui->legendComboBox->addItem("No Legend ", 0);
    m_ui->legendComboBox->addItem("Legend Top", Qt::AlignTop);
    m_ui->legendComboBox->addItem("Legend Bottom", Qt::AlignBottom);
    m_ui->legendComboBox->addItem("Legend Left", Qt::AlignLeft);
    m_ui->legendComboBox->addItem("Legend Right", Qt::AlignRight);
  • 遍历设置全部图表的侧面显示。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Qt::Alignment alignment(
    m_ui->legendComboBox->itemData(m_ui->legendComboBox->currentIndex()).toInt());

    if (!alignment) {
    for (QChartView *chartView : charts)
    chartView->chart()->legend()->hide();
    } else {
    for (QChartView *chartView : charts) {
    chartView->chart()->legend()->setAlignment(alignment);
    chartView->chart()->legend()->show();
    }
    }

0x05 图表抗锯齿

  抗锯齿开启后会对性能造成影像但会改善显示效果。

1
2
3
bool checked = m_ui->antialiasCheckBox->isChecked();
for (QChartView *chart : charts)
chart->setRenderHint(QPainter::Antialiasing, checked);

0x06 关于更多

  • 在QtCreator软件可以找到:

插图

  • 或在以下Qt安装目录找到

    1
    C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\charts\chartthemes
  • 相关链接

    1
    https://doc.qt.io/qt-5/qtcharts-chartthemes-example.html
  • Qt君公众号回复『Qt示例』获取更多内容。

Qml组件小知识

发表于 2019-10-19

介绍组件构造,销毁,动态加载小知识。

对象/组件都具有类似C++的构造函数和析构函数

  • onCompleted对象构造完成自动执行;
  • onDestruction对象销毁前自动执行。
    1
    2
    3
    4
    QtObject {
    Component.onCompleted: console.log("Completed")
    Component.onDestruction: console.log("Destruction")
    }

使用Loader加载组件

  • Component必须具有子空间才能实例化;
  • onProgressChanged可以获取到组件的加载进度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Component {
    id: component
    Text {
    text: "Component"
    }
    }

    Loader {
    sourceComponent: component
    onProgressChanged: console.log(progress)
    }

动态加载Qml组件(1)

  • 原型:
  1. qml为qml组件描述语句;
  2. parent为依附于那个父类控件;
  3. filepath为重定向到文件的加载过程中的错误报告
    1
    2
    3
    object createQmlObject(qml, 
    object parent,
    string filepath)
  • 例子
    1
    2
    3
    var object = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "blue"; width: 50; height: 50}',
    root,
    "error.txt");

动态加载Qml组件(2)

  • 原型:
  1. url为qml文件(还可以加载网络qml文件);
  2. mode为创建qml的模式(同步或异步);
  3. parent指定某个控件为父类控件;
  4. object为附加属性。
    1
    2
    object createComponent(url, mode, parent)
    object createObject(parent, object properties)
  • 示例:
    1
    2
    3
    var component = Qt.createComponent("MyComponent.qml");
    if (component.status == Component.Ready)
    component.createObject(parent, {x: 100, y: 100});

使用python批量编译Qt工程的脚本

发表于 2019-10-17

使用python脚本编写而成,主要用于windows平台(msvc编译器)。

部署环境

  设置脚本内的build_list变量的值即可。

  • qmake.exe路径;
  • jom.exe路径;
  • 编译环境变量;
  • 编译项目。

源码

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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import os
import datetime
import subprocess

build_list = [
{
'qmake': r'C:\Qt\Qt5.12.2\5.12.2\msvc2017_64\bin\qmake.exe',
'qmake_params': r'"CONFIG+=qtquickcompiler"',
'jom': r'C:\Qt\Qt5.12.2\Tools\QtCreator\bin\jom.exe',
'env_bat': r'C:\"Program Files (x86)"\"Microsoft Visual Studio"\2017\Community\VC\Auxiliary\Build\vcvarsall.bat amd64',
'project': r'C:\Users\Document\Example.pro'
}
]

class Builder:
def __init__(self, project, qmake, qmake_params, jom, env_bat):
self.project = project
self.qmake = qmake
self.qmake_params = qmake_params
self.jom = jom
self.env_bat = env_bat

(self.qmake_path, self.qmake_name) = os.path.split(qmake)
(self.jom_path, self.jom_name) = os.path.split(jom)
(self.project_path, self.project_name) = os.path.split(project)

self.qt_version = self.qmake_path.split('\\')[-3]
self.compiler_version = self.qmake_path.split('\\')[-2]

def execute_qmake_cmd_line(self):
create_qmake_cmd_line = self.qmake + ' ' + self.project + ' -spec win32-msvc ' + self.qmake_params
return True if execute(create_qmake_cmd_line) else False

def execute_make_cmd_line(self):
cmd_line = '{0} -j8'.format(self.jom)
return True if execute(cmd_line) else False

def execute_make_clean_cmd_line(self):
if os.path.exists('Makefile') | os.path.exists('makefile'):
return True if execute('{0} clean'.format(self.jom)) else False

return True

def init_env(self):
tmp = os.popen("{0} && {1}".format(self.env_bat, 'set'))
env_str = tmp.read()
tmp.close()

env_list = str(env_str).split('\n')

for each in env_list:
if '=' in each:
key = each.split('=')[0].lower()
value = each.split('=')[1]
os.environ[key] = value

return True

def build(self):
os.chdir(self.project_path)
print('Starting build [{0}]'.format(os.path.splitext(self.project_name)[0]))

isOk = True
status = self.init_env()
isOk = isOk and status
print('Init env: ', 'Success' if status else 'Failed')

status = self.execute_make_clean_cmd_line()
isOk = isOk and status
print('Make clean: ', 'Success' if status else 'Failed')

status = self.execute_qmake_cmd_line()
isOk = isOk and status
print('QMake: ', 'Success' if status else 'Failed')

status = self.execute_make_cmd_line()
isOk = isOk and status
print('Make: ', 'Success' if status else 'Failed')

print('End build ', 'Success' if isOk else 'Failed')
return isOk

def execute(cmd):
result = subprocess.run(cmd, encoding='gbk',shell=True, capture_output=True)
if result.returncode != 0:
print(result.stdout, result.stderr)

return True if result.returncode == 0 else False

def update_project_code(project_path, branch):
print('Update ', project_path)
os.chdir(project_path)
return execute('git pull origin ' + branch)


def update_code(build_list):
print('Updating...')
for each in build_list:
project = '' if each.get('project') == None else each.get('project')
path = os.path.split(project)[0]
if not update_project_code(path, 'master'):
print('Updated failed')
exit(-1)

print('Updated success')

def build(build_list):
for each in build_list:
qmake = each.get('qmake')
qmake_params = '' if each.get('qmake_params') == None else each.get('qmake_params')
jom = each.get('jom')
env_bat = each.get('env_bat')
project = each.get('project')

builder = Builder(project, qmake, qmake_params, jom, env_bat)
if (builder.build() == False):
print('[{0}] Deploy failed!!!'.format(datetime.datetime.now()))
exit(-1)


if __name__ == '__main__':
print('[{0}] Start deploy...'.format(datetime.datetime.now()))
# update_code(build_list)
build(build_list)
print('[{0}] Deploy success!!!'.format(datetime.datetime.now()))

qDebug | std::cout | printf性能表现

发表于 2019-10-17

Qt君最近感觉qDebug相对于printf打印感觉有些慢,但又没有证据,于是闲着就写下qDebug,std::cout,printf的性能表现咯。注:测试数据仅供参考。

0x00 测试环境

环境 参数
CPU i5-8250U
内存 8G
操作系统 Windows@64位
Qt版本 Qt 5.12.1
编译器 MSVC2017@64位

0x01 数据呈现

  通过使用qDebug,std::cout,printf在1秒内打印的字符串数据。

  • 分别各测试10次后取平均值,详细数据在文末。
debug版本(次/秒) release版本(次/秒)
qDebug 38317 60923
std::cout 382890 372696
printf 432606 386663
  • 图表化显示

插图

0x02 数据分析

  • 性能表现:printf > std::cout > qDebug;
  • qDebug()相对于std::cout和printf差距过大(6~10倍);
  • std::cout与printf数据基本一致;
  • std::cout与printf的debug与release差距不大,甚至有debug比release快的现象(可能受实验环境影响)。

0x03 结论

  • qDebug比std::cout和printf慢,高频调用有可能影响系统时延;
  • 性能均衡推荐选用std::cout;
  • 追求性能选用printf。

0x04 测试程序

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
#include <QDebug>
#include <QElapsedTimer>
#include <iostream>

/* 注:单独打开某个宏测试 */
//#define TEST1
//#define TEST2
//#define TEST3

int main(int argc, char *argv[])
{
#ifdef TEST1
{
QElapsedTimer t;
qint64 it = 0;
t.start();
while (t.elapsed() < 1000) {
qDebug() << "Test1";
it++;
}

qDebug() << "Test1: " << it;
}
#endif

#ifdef TEST2
{
QElapsedTimer t;
qint64 it = 0;
t.start();
while (t.elapsed() < 1000) {
std::cout << "Test2" << std::endl;
it++;
}

std::cout << "Test2: " << it;
}
#endif

#ifdef TEST3
{
QElapsedTimer t;
qint64 it = 0;
t.start();
while (t.elapsed() < 1000) {
printf("Test3\n");
it++;
}

printf("Test3: %lld\n", it);
}
#endif
return 0
}

0x05 测试数据(各10次)

  • debug版本

    1
    2
    3
    4
    5
    6
    7
    8
    qDebug: 
    38310 38452 39416 38420 38962 38385 39293 38814 34178 38946

    std::cout:
    389512 397234 378168 367970 366371 364401 405547 405992 365863 387846

    printf:
    468310 423937 480598 385025 490155 489473 373419 397995 445099 372054
  • release版本

    1
    2
    3
    4
    5
    6
    7
    8
    qDebug: 
    60779 60710 59450 59685 63298 61044 59788 61167 61822 61495

    std::cout:
    352541 358754 377001 380487 397576 362145 333757 413027 416352 335320

    printf:
    468310 329729 333142 320171 333825 330411 471041 473771 468310 337921

翻译 | 您没有做错(线程)

发表于 2019-10-16

本文翻译自: https://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html
原作者: Olivier Goffart
发布时间:2013年1月22日

  这篇文章是关于QThread的使用的。这是对我当时的同事Brad三年前的博客帖子的回答:”您做错了”。

  Brad在他的博客文章中解释说,他看到许多用户通过对QThread进行子类化,在该子类中添加一些槽并在构造函数中执行以下操作来滥用QThread:

1
moveToThread(this);

  他们把线程移动到自己类内。正如Brad所提到的,这是错误的:QThread应该是管理线程的接口。因此,应该在创建线程中使用它。

  这样,就无法在该线程中运行QThread对象中的槽,并且在QThread的子类中具有槽是一种不好的做法。

  但是,Brad继续并完全不鼓励使用QThread的任何子类。他声称这违反了正确的面向对象设计。这是我不同意的地方。放入代码run()是扩展QThread的一种有效的面向对象方法:QThread表示一个仅启动事件循环的线程,子类表示一个被扩展以执行其工作的线程run()。

  Brad上任后,该社区的一些成员就反对对QThread进行子类化进行了讨伐。问题在于,有很多完全合法的原因可以继承QThread。

  在Qt 5.0和Qt 4.8.4中,更改了QThread的文档,因此示例代码不涉及子类。查看Qt 4.8 QThread文档的第一个代码示例(更新的文档已经修复)。它具有许多样板行,仅用于在线程中运行一些代码。而且甚至存在泄漏:QThread永远不会退出并被销毁。

  我在IRC上被问到一个用户的问题,该用户遵循该示例,以便在线程中运行一些简单的代码。他很难弄清楚如何正确销毁线程。这就是促使我撰写此博客条目的原因。

  如果允许子类化QThread,那么您将获得:

1
2
3
4
5
6
7
8
9
10
11
12
13
class WorkerThread : public QThread {
void run() {
// ...
}
};

void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread;
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
workerThread->start();
}

  此代码不再泄漏,并且更加简单,并且不会创建无用的对象,因此开销较小。

  Qt线程示例threadedfortuneserver是使用此模式运行阻塞操作的示例,并且比使用worker对象的等效示例要简单得多。

  我已经向文档提交了补丁, 以免再次阻止对QThread的子类化。

经验法则


什么时候子类化,什么时候不子类化?

  • 如果您确实不需要线程中的事件循环,则应该子类化。
  • 如果需要事件循环并处理线程中的信号和槽,则可能不需要子类化。

改用QtConcurrent呢?

  QThread的级别很低,您最好使用更高级别的API,例如QtConcurrent。

  现在,QtConcurrent有其自身的一系列问题:它与单个线程池绑定,因此如果要运行阻塞操作,它不是一个好的解决方案。在其实现中还存在一些问题,这些问题会带来一些性能开销。所有这些都是可以修复的。也许甚至Qt 5.1也会有所改进。

  一个很好的选择也是C ++ 11与标准库 std::thread 和std::async它们现在在一个线程中运行的代码的标准方式。好消息是它仍然可以在Qt上正常工作:所有其他Qt线程原语都可以与本机线程一起使用。(如果需要,Qt将自动创建一个QThread来创建)

关于更多

  • 请查看往期文章「你这样做是错的…(翻译文)」

QString重复字符生成

发表于 2019-10-14

使用QString生成重复字符,避免使用复杂繁琐的循环语句生成。

通过构造函数生成

  构造一个给定大小的字符串,且每个字符为ch。

1
QString::QString(int size, QChar ch)

1
2
QString str = QString(5, '+')
// str == "+++++"

使用fill接口实现

  将字符串中的每个字符设置为ch。如果大小不同于-1(默认值),则预先将字符串调整为指定size大小。

1
QString &QString::fill(QChar ch, int size = -1)

1
2
3
4
5
6
QString str = "Hello";
str.fill('+');
// str == "+++++"

str.fill('-', 3);
// str == "---"

为QtCreator添加一键打包工具

发表于 2019-10-14

用图文的方式教大家如何添加。

0x00 设置入口

插图

0x01 添加工具

插图

0x02 配置打包工具环境

  填入下列参数到对应栏目下。由于打包工具会在执行文件目录下生成打包依赖文件,建议在项目文件(.pro)中使用DESTDIR指定执行文件的生成路径。

  • 执行档:

    1
    %{CurrentProject:QT_HOST_BINS}\windeployqt.exe
  • 参数:

    1
    %{CurrentRun:Executable:FilePath}
  • 工作目录:

    1
    %{CurrentRun:Executable:NativePath}

插图

0x03 效果

插图

利用qmake分类编译输出的中间文件

发表于 2019-10-13

通过配置项目文件控制编译器分类生成中间文件,中间文件较多时作用较大。

DESTDIR

  • 设置执行文件的输出目录,如(.exe文件)。

OBJECTS_DIR

  • 设置编译时生成的中间代码文件的路径。

MOC_DIR

  • 设置编译时生成moc文件的路径。
  • 注:所有QObject派生的类都会生成moc。

RCC_DIR

  • 设置编译时资源文件的路径。
  • 注:把图片放到qrc里面,使用编译器生成qrc_xxx.cpp文件。

UI_DIR

  • 设置编译时ui界面文件的路径。
  • 注:如存在xxx.ui文件则编译器生成名为ui_xxx.h文件

qmake分类语句

1
2
3
4
5
6
7
8
9
10
11
12
build_type =
CONFIG(debug, debug|release) {
build_type = debug
} else {
build_type = release
}

DESTDIR = $$build_type/out
OBJECTS_DIR = $$build_type/obj
MOC_DIR = $$build_type/moc
RCC_DIR = $$build_type/rcc
UI_DIR = $$build_type/ui

设置分类语句前

插图

设置分类语句后

  • 齐齐整整的目录分类

插图

  • 目录树
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ├─moc
    │ moc_mainwindow.cpp
    │ moc_predefs.h
    │
    ├─obj
    │ main.obj
    │ mainwindow.obj
    │ moc_mainwindow.obj
    │ qrc_rcc.obj
    │ TextEdit_resource.res
    │
    ├─out
    │ TextEdit.exe
    │
    ├─rcc
    │ qrc_rcc.cpp
    │
    └─ui
    ui_mainwindow.h
1…345…32
Qt君

Qt君

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