在C++中,使用字符串相对于char *,我更倾向于使用string。其优点更安全,更多的易用接口。
简化的string类似于下列实现,除了比char 多几个字节的占用空间外几乎一样,但比char 省心很多,这也是C++的”++”表现之一。1
2
3
4struct string {
char* data;;
size_t length;
};
在C++中,使用字符串相对于char *,我更倾向于使用string。其优点更安全,更多的易用接口。
简化的string类似于下列实现,除了比char 多几个字节的占用空间外几乎一样,但比char 省心很多,这也是C++的”++”表现之一。1
2
3
4struct string {
char* data;;
size_t length;
};
一个类如果不继承QObject是不能直接使用tr函数,有什么方法可以在不继承QObject的情况下又能直接使用tr函数呢?答案是使用Q_DECLARE_TR_FUNCTIONS宏。
tr
与trUtf8
静态方法。1 | static inline QString tr(const char *sourceText, |
1 | class Test |
在2019/09/25的Qt5.14评估版本中看到QTextEdit和QTextBrowser支持markdown格式。编写文本(笔记,文章等)上markdown相对于html语法,其简洁,方便,高效。
1 | # 1.标题 |
一直来被问得最多的是关于windows系统上程序打包上问题,不能运行,在我的机器能运行,别的机器不能运行的情况。经过一段时间的整理,将一些问题和解决方法都列出来供大家参考。
小白:怎么我编译好的程序在QtCreator能运行,但我在文件夹下打开却不行了呢?
Qt君:因为QtCreator运行下的程序附带了运行环境,而离开了QtCreator软件没有运行环境会报以下的一些错误(库找不到)。
小白:那我该怎么找这些库呢?
Qt君:你可以根据你的编译配置(Qt版本,编译器,32/64位,release/debug)来选用不同的windeployqt.exe工具帮你生成Qt依赖的运行库。
一般程序生成方法:
1 | windeployqt xxx.exe |
如果是使用QML组件需要这样操作:
1 | windeployqt xxx.exe --qmldir qmlPath |
注意: 请使用Qt提供的控制台操作。
小白:怎么会出现PTLib.dll
找不到的问题?
Qt君:由于windeploqt.exe工具并不能找到第三方库,这时候需要自己对应将库复制到程序的运行目录下。
小白:0xc000007b错误代码这个又怎么了?
Qt君:可能是你打包时候使用了版本不对应的windeploqt.exe工具,你当时使用的是什么版本的windeploqt.exe?
小白:Qt5.12.2 (MSVC 2017 64-bit)
Qt君:你的程序版本是Qt5.12.2 (MSVC 2017 32-bit),而windeploqt.exe版本是生成64位的库不对咯,你修改为对应的windeploqt.exe就可以了。
小白:”无法找到入口”?
小白:哦,我明白了。我使用了mingw版本的windeploqt.exe与程序使用MSVC编译器不一样导致生成的程序库找不到入口。
Qt君:不错,学会举一反三了。
小白:现在才举一反二,还差一例就举一反三了。在使用windeploqt.exe过程中,看到有一个--release
参数,在msvc的windeploqt.exe下似乎默认为release
参数,但我使用mingw时候却生成的是debug版本的程序库(例:Qt5Cored.dll带d
标识)。我还是每次生成之前都输入--release
或--debug
参数了,以防万一。
小白:这个问题很诡异,它又不提示库找不到,就显示了这信息,该怎么解决呢?
Qt君:造成这一问题有很多,但最有可能的是没有生成platforms/qwindows.dll
插件。你可以尝试删除目录下的库再重新生成试一试,或者在对应的Qt安装目录下复制platforms/qwindows.dll
插件到自己程序的运行目录下。注意要带上platforms目录
。
小白:我用本机能运行,但在其他机器不能运行?
Qt君:主要是缺windows相关库。
复制以下路径的库文件到运行目录下:1
2C:\Windows\System32 (注意:32位编译程序复制)
C:\Windows\SysWOW64 (注意:64位编译程序复制)
小白:这次太糟了,双击程序完全没反应,只是一个简单的QML应用,怎么回事呀?
Qt君:由于QML应用大量使用了插件形式的缘故吧。比如import QtQuick.Shapes 1.12
则会在程序运行时加载Shapes
模块插件。你可以这样,在程序的项目文件添加CONFIG += console
然后在命令行执行,看调试输出。因为qml没有断言输出,导致不能弹框警告错误。
小白:运行后看调试输出貌似是缺少Shapes模块。1
2
3C:\Users\Strong\Documents\Deploy>Test.exe
QQmlApplicationEngine failed to load component
qrc:/main.qml:3 module "QtQuick.Shapes" is not installed
Qt君:由于windeploqt.exe工具并不能解析到程序加载的插件,这就导致某些插件没有被复制到,需要手动复制添加Shapes
插件。
解决方法:
将Shapes目录
1 | C:\Qt\Qt5.12.2\5.12.2\msvc2017\qml\QtQuick\Shapes |
复制到运行目录(C:\Users\Strong\Documents\Deploy
)的QtQuick目录下
1 | C:\Users\Strong\Documents\Deploy\QtQuick |
如出现以下问题还需要将Qt5QuickShapes.dll
复制到程序运行目录下1
2
3C:\Users\Strong\Documents\Deploy>Test.exe
QQmlApplicationEngine failed to load component
qrc:/main.qml:3 plugin cannot be loaded for module "QtQuick.Shapes": Cannot load library C:\Users\Strong\Documents\Deploy\QtQuick\Shapes\qmlshapesplugin.dll
将Qt5QuickShapes.dll
文件
1 | C:\Qt\Qt5.12.2\5.12.2\msvc2017\bin\Qt5QuickShapes.dll |
复制到运行目录下
1 | C:\Users\Strong\Documents\Deploy\ |
depends.exe
。 解决使用protobuf库过程中出现的编译问题。protobuf和XML,json一样的数据结构。
缺protobuf库,可以定义PROTOBUF_USE_DLLS
来链接protobuf库。
1 | 无法解析的外部符号 "class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits,class std::allocator > > |
解决方法:
1 | DEFINES += PROTOBUF_USE_DLLS |
std::min,std::max与windows.h的min,max冲突了。
1 | .pb.h:189: warning: C4003: 类函数宏的调用“min”参数不足 |
解决方法:
屏蔽windows.h的min, max方法
1 | DEFINES += NOMINMAX |
该刻度盘控件为一个速度仪表盘。
使用到了图片素材(刻度盘,指示器,指示器阴影,覆盖层);
它结合了Image元素,Rotation变换和SpringAnimation行为,用来组合生成交互式的速度仪表盘。
1 | Item { |
在QtCreator软件可以找到:
或在你的Qt安装目录C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\quick\customitems\dialcontrol
找到。
相关链接
1 | https://doc.qt.io/qt-5/qtquick-customitems-dialcontrol-example.html |
Qt君公众号后台回复『Qt示例』获取更多内容。
libpng warning: iCCP: known incorrect sRGB profile
新版本(libpng-1.6)在检查ICC配置文件(主要用于色彩校正)方面更加严格。您可以忽略该警告,但有些应用程序会将该警告处理为错误。
删除PNG图像中iCCP块。为大家提供以下两种方法。
Unix系统下可以使用convert
工具转换
1 | convert in.png out.png |
可以使用Qt库实现来转换
1 | QPixmap pixmap; |
Qt翻译功能最近用得好好的,却是一份新需求导致对这一功能的思考。
最近接到一个新需求就是为公司的某个软件添加多语言翻译功能,由于之前已经做过类似的了。直接移植就可以了。可是实际上并不是那么简单,多语言共有9种。可是翻译人员不会用Qt的语言家软件。除了中英文自己翻译外,其余的7种语言都需要发给专门的翻译人员翻译。7种语言翻译都统一弄成excel文本给他们翻译,当他们翻译完成后又一个一个对应的填在语言家软件里,这操作做了两份语言后,实在是受不了了。心里碎碎念:这到底是什么翻译操作啊,太繁琐了。
于是我不发excel文档给他们翻译了,和他们说你翻译到Qt的语言家软件吧。教他们安装Qt语言家,并教他们如何使用。说多是泪,我一顿操作猛如虎,一问他们会不会,都说太难了!只好放弃这一想法。顿时陷入沉思中,究竟是谁走漏了风声说:Qt翻译很简单的!!!
还有就是,语言家提供提取Qt项目文件的翻译到文件,我想说的是这操作挺好的。但每次翻译字段更改的时候又要重新刷新一下翻译文件,这设计太难用了。我们常用的思维应该是修改翻译文本,再通过翻译文本去修改Qt项目的翻译字段。
常常我们不论翻译和不翻译的文本都使用tr()
包含一下,但这是用错了,或许有人会说:可以解决乱码问题呀。只能说有些系统能解决乱码问题。在没有翻译功能的前提下使用tr()
会造成额外性能负担。还有就是tr()
会根据类名标记翻译字段,这一点很想不明白。作者可能是使用类似命名空间的做法来实现翻译字段的命名空间限制,实际使用上只会增加额外的使用负担和学习成本。
回到最初问题(重复工作多),没办法只能写一个小工具(csv转qm),csv格式文件可以被excel打开,而工具可以直接将csv文件转换为翻译二进制(qm后缀文件),这样就可以避免一个一个复制到语言家再翻译了。而对翻译人员也相对友好。
Qt君公众号回复『工具』获取该工具
在原有的键盘基础上新增中文输入功能。
中文输入候选栏ChineseWidget
使用QListWidget和样式表实现:
setText
输入对应拼音字母,即会加载符合的拼音中文。pressedChanged
信号函数即为当按键按下,传递对应的中文。1
2
3
4
5
6
7
8
9
10class ChineseWidget : public QListWidget {
Q_OBJECT
public:
ChineseWidget(QWidget *parent = NULL);
void setText(const QString &text);
signals:
void pressedChanged(const int &code, const QString &text);
...
};
设置QListWidget: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
27setFocusPolicy(Qt::NoFocus);
/* 设置为列表显示模式 */
setViewMode(QListView::ListMode);
/* 从左往右排列 */
setFlow(QListView::LeftToRight);
/* 屏蔽水平滑动条 */
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
/* 屏蔽垂直滑动条 */
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
/* 设置为像素滚动 */
setHorizontalScrollMode(QListWidget::ScrollPerPixel);
/* 设置鼠标左键拖动 */
QScroller::grabGesture(this, QScroller::LeftMouseButtonGesture);
/* 设置样式 */
setStyleSheet(R"(
QListWidget { outline: none; border:1px solid #00000000; color: black; }
QListWidget::Item { width: 50px; height: 50px; }
QListWidget::Item:hover { background: #4395ff; color: white; }
QListWidget::item:selected { background: #4395ff; color: black; }
QListWidget::item:selected:!active { background: #00000000; color: black; }
)");
字库加载在QMap<QString, QList<QPair<QString, QString>> >
容器中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20QFile pinyin(":/ChineseLib/PinYin");
if (! pinyin.open(QIODevice::ReadOnly)) {
qDebug() << "Open pinyin file failed!";
return;
}
while (! pinyin.atEnd()) {
QString buf = QString::fromUtf8(pinyin.readLine()).trimmed();
QRegExp regExp("^[\u4E00-\u9FA5]+");
int index = regExp.indexIn(buf);
if (index == -1)
continue;
QString first = buf.right(buf.size() - regExp.matchedLength()); // 分离拼音字母
QString second = buf.mid(index, regExp.matchedLength()); // 分离中文
QList<QPair<QString, QString>> &tmp = m_data[first.left(1)]; // 取首字母做索引
tmp.append(qMakePair(first, second));
}
部分字库内容预览:1
2
3
4
5
6
7
8
9
10
11
12
13
14安a
按a
爱a
阿a
暗a
啊a
埃a
碍a
凹a
奥a
岸a
矮a
案a
俺a
取拼音首字母索引,再匹配中文。1
2
3
4
5
6
7const QList<QPair<QString, QString>> &tmp = m_data[text.left(1)];
for (const QPair<QString, QString> &each : tmp) {
if (each.first != text) // 匹配是否符合的在容器里面拼音
continue;
addOneItem(each.second);
}