QT实用小技巧(想到就更新)

日志打印:Release下打印行号和文件名

The class provides information about the source code location a qDebug(), qInfo(), qWarning(), qCritical() or qFatal() message was generated.
Note: By default, this information is recorded only in debug builds. You can overwrite this explicitly by defining QT_MESSAGELOGCONTEXT or QT_NO_MESSAGELOGCONTEXT.

pro或者pri文件内加入

1
DEFINES += QT_MESSAGELOGCONTEXT

Release下生成调试文件(win:pdb)

pro或者pri文件内加入

1
2
QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE += $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO

高分屏适配

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
void setHighDpiEnvironmentVariable()
{
if (Utils::HostOsInfo().isMacHost())
return;

if (Utils::HostOsInfo().isWindowsHost() && !qEnvironmentVariableIsSet("QT_OPENGL")) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif
}

if (Utils::HostOsInfo().isWindowsHost()
&& !qEnvironmentVariableIsSet("QT_DEVICE_PIXEL_RATIO") // legacy in 5.6, but still functional
&& !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR")
&& !qEnvironmentVariableIsSet("QT_SCALE_FACTOR")
&& !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
}
#if defined(Q_OS_WIN) && (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
}

或者添加资源文件(:/qt/etc/qt.conf)

1
2
3
[Platforms]
WindowsArguments = fontengine=freetype
WindowsArguments = dpiawareness=0

窗口居中(去掉任务栏的区域居中)

1
2
3
4
5
6
7
8
9
void windowCenter(QWidget *window)
{
const QRect rect = qApp->primaryScreen()->availableGeometry();
int x = (rect.width() - window->width()) / 2 + rect.x();
int y = (rect.height() - window->height()) / 2 + rect.y();
x = qMax(0, x);
y = qMax(0, y);
window->move(x, y);
}

字体加载

1
int QFontDatabase::addApplicationFont(const QString &fileName)

Loads the font from the file specified by fileName and makes it available to the application. An ID is returned that can be used to remove the font again with removeApplicationFont() or to retrieve the list of family names contained in the font.
The function returns -1 if the font could not be loaded.
Currently only TrueType fonts, TrueType font collections, and OpenType fonts are supported.
Note: Adding application fonts on Unix/X11 platforms without fontconfig is currently not supported.
See also addApplicationFontFromData(), applicationFontFamilies(), and removeApplicationFont().

给生成文件添加信息(windows)

1. 在Pro或者pri文件中添加以下信息

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
#中文(简体)
RC_LANG = 0x0004

#产品版本
VERSION = 0.0.0.1

#产生文件名字忽略主版本号(VERSION)
CONFIG += skip_target_version_ext

#公司名称
QMAKE_TARGET_COMPANY = The Qt Company Ltd.

#文件说明
QMAKE_TARGET_DESCRIPTION = C++ Application Development Framework

#版权
QMAKE_TARGET_COPYRIGHT = Copyright (C) 2021 The Qt Company Ltd.

#产品名称
QMAKE_TARGET_PRODUCT = Qt5

#原始文件名
QMAKE_TARGET_ORIGINAL_FILENAME = Qt5

#内部名称
QMAKE_TARGET_INTERNALNAME = AppPlugin

#评论
QMAKE_TARGET_COMMENTS = C++ Application Development Framework

#商标
QMAKE_TARGET_TRADEMARKS = Qt

2. 添加.rc文件

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
#include <windows.h>

IDI_ICON1 ICON "D:\\Mine\\CODE\\Qt\\AppTools\\app-subdir\\app\\app.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,0,0,1
PRODUCTVERSION 0,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000404b0"
BEGIN
VALUE "CompanyName", "The Qt Company Ltd.\0"
VALUE "FileDescription", "C++ Application Development Framework\0"
VALUE "FileVersion", "0.0.0.1\0"
VALUE "LegalCopyright", "Copyright (C) 2021 The Qt Company Ltd.\0"
VALUE "OriginalFilename", "Qt5\0"
VALUE "ProductName", "Qt5\0"
VALUE "ProductVersion", "0.0.0.1\0"
VALUE "InternalName", "Qt5\0"
VALUE "Comments", "C++ Application Development Framework\0"
VALUE "LegalTrademarks", "Qt\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0004, 1200
END
END
/* End of Version info */

如果变量值是中文,需要将.pro文件以system本地编码保存。

MAC下直接修改Info.plist

例子:qt-creator的info.plist

警告当成错误处理和忽略警告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#将所有的警告当成错误处理
QMAKE_CXXFLAGS += \
-Werror = return-type \#函数有返回值
-Werror = return-local-addr \#返回局部变量地址
-Werror = missing-field-initializers \#缺少初始值设定项
-Werror = maybe-uninitialized \#变量可能没有被初始化
-Werror = delete-non-virtual-dtor \#
-Werror = unused-but-set-variable \#设置了但未使用的变量
-Werror = parentheses \#括号不匹配
-Werror = pointer-arith \#指针用在了算术运算
-Werror = reorder \#警告构造函数的顺序不会被使用
-Werror = format-extra-args \#格式不对
-Werror = format= \#格式不对
-Werror = unused-variable \#未使用的变量

#忽略该警告
QMAKE_CXXFLAGS += \
-Wno-unused-function \#未使用的函数
-Wno-unused-parameter \#设置了但未使用的参数
-Wno-comment \#注释使用不规范。
-Wno-sequence-point \#如出现i=i++这类代码,则报警告

继承QWidget的子类样式表不生效

Supports only the background, background-clip and background-origin properties.If you subclass from QWidget, you need to provide a paintEvent for your custom QWidget as below:

机翻:

仅支持 background、background-clip 和 background-origin 属性。如果你从 QWidget 继承,你需要为你的自定义 QWidget 提供一个paintEvent,如下所示:

1
2
3
4
5
6
7
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

The above code is a no-operation if there is no stylesheet set.

Warning: Make sure you define the Q_OBJECT macro for your custom widget.

机翻:

如果没有设置样式表,上面的代码是无操作的。

警告:确保为自定义小部件定义 Q_OBJECT 宏。

其他方案

  1. setAttribute(Qt::WA_TranslucentBackground);
  2. 从QFrame继承;

国际化实时翻译

  1. 需要翻译的文字带上QCoreApplication::translate或者QObject::tr,比如QObject::tr("Hello")
  2. 使用QtCreator工具-外部-Qt语言家更新翻译;
  3. 使用Linguist打开文件进行翻译;
  4. 使用QtCreator工具-外部-Qt语言家发布翻译;
  5. 使用QTranslator加载翻译文件;
  6. QCoreApplication::installTranslator(&translator)

以上操作仅支持程序打开时翻译,程序运行中则无效,需加入以下代码:

  1. 使用QCoreApplication::removeTranslator移除上一次的翻译;
  2. 构造新的QTranslator,并加载翻译;
  3. QCoreApplication::installTranslator(&translator)
1
2
3
4
5
6
7
8
9
10
11
12
void Widget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
comboBox->setItemText(0, tr("Hello"));
label->setText(tr("Hello")); // 代码添加的文字
ui->retranslateUi(this); // 有UI文件情况下
break;
default: break;
}
}

QIcon添加不同状态的图标

1
2
void QIcon::addFile(const QString &fileName, const QSize &size = QSize(), QIcon::Mode mode = Normal, QIcon::State state = Off)
void QIcon::addPixmap(const QPixmap &pixmap, QIcon::Mode mode = Normal, QIcon::State state = Off)

加载字体

1
[static] int QFontDatabase::addApplicationFont(const QString &fileName)

隐式共享和显示共享(MVC好帮手)

QSharedData + QSharedDataPointer = 隐式共享:修改数据即拷贝;

QSharedData + QExplicitlySharedDataPointer = 显示共享:即永远只有一个数据源(除非手动调用detach());

Qt文档有具体例子和说明,以下是从Qt中复制的代码:

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
#include <QSharedData>
#include <QString>

class EmployeeData : public QSharedData
{
public:
EmployeeData() : id(-1) { }
EmployeeData(const EmployeeData &other)
: QSharedData(other), id(other.id), name(other.name) { }
~EmployeeData() { }

int id;
QString name;
};

class Employee
{
public:
Employee() { d = new EmployeeData; }
Employee(int id, const QString &name) {
d = new EmployeeData;
setId(id);
setName(name);
}
Employee(const Employee &other)
: d (other.d)
{
}
void setId(int id) { d->id = id; }
void setName(const QString &name) { d->name = name; }

int id() const { return d->id; }
QString name() const { return d->name; }

private:
QSharedDataPointer<EmployeeData> d;
//改成QExplicitlySharedDataPointer<EmployeeData> d;即为显示共享
};

使用MVC,建议使用显示共享,任意位置修改数据,都会反映到显示的视图上

void QComboBox::setMaxVisibleItems(int maxItems)无效

1
comboBox->setStyleSheet("QComboBox {combobox-popup:0;}");

使用QT style内置的图标

1
[pure virtual] QIcon QStyle::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const

QPushButton和QToolButton setMenu去掉下拉小箭头

1
2
3
4
QPushButton::menu-indicator,
QToolButton::menu-indicator{
image:none;
}

禁止输入中文

1
setAttribute(Qt::WA_InputMethodEnabled, false);

设置动态链接库的加载路径 rpath

1. qmake(.pro)

1
QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN/lib\'" 

$ORIGIN代表可执行程序所在路径

2. cmake

1
2
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
set_target_properties(myexe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

选择一种,建议第二行,指定某个执行程序或者动态库连接到这个路径

3. chrpath(linux)

1
chrpath -r "/opt/MyApplication/lib/" MyApplication

输出:

1
2
application: RUNPATH=/usr/lib
application: new RUNPATH: /opt/MyApplication/lib/

MacOS 库链接版本问题

1
dyld: Symbol not found: __cg_jpeg_resync_to_restart

解决

This is only a QtCreator runtime issue. DanyAlejandro’s answer (above) is partially correct.

  1. Go to Projects -> Run -> “Run Environment” (show Details)
  2. I would not recommend Unset, rather you should edit Both: DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH
  3. Add /System/Library/Frameworks/ImageIO.framework/Resources: to the beginning for both paths (colon delimited string)
  4. Build project again - this will fix it for good

MacOS 去掉焦点的蓝色轮廓

1
setAttribute(Qt::WA_MacShowFocusRect, false); 

Indicates that this widget should get a QFocusFrame around it. Some widgets draw their own focus halo regardless of this attribute. Not that the QWidget::focusPolicy also plays the main role in whether something is given focus or not, this only controls whether or not this gets the focus frame. This attribute is only applicable to macOS.

机翻:

指示这个小部件应该在它周围获得一个 QFocusFrame 。 无论此属性如何,一些小部件都会绘制自己的焦点光环。 并不是说 QWidget::focusPolicy 在是否获得焦点方面也起着主要作用,这仅控制是否获得焦点框。 此属性仅适用于 macOS。

MacOS 屏蔽深色模式

在Info.plist文件的<dict>节点加入以下字段:

1
2
<key>NSRequiresAquaSystemAppearance</key>
<true/>

MacOS QHBoxLayout添加的QPushButton矩形范围溢出

1
pushButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);

MacOS QSystemTrayIcon主窗口关闭后,无法从程序坞图标再次打开窗口问题

setQuitOnLastWindowClosed(false),关闭主窗口后,点击程序坞图标无法再次打开窗口;
解决方法:

1
connect(qApp, &QApplication::ApplicationStateChanged, this, &MainWindow::onApplicationStateChanged);
1
2
3
4
5
6
void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
{
if (state == Qt::ApplicationActive){
this->show();
}
}

Wait a minute