1. visual studio 编译报错 ''无法解析的外部命令(外部符号)":可能是函数中参数类型的前置声明有问题,比如将struct ClassName;
不小心声明为class ClassName;
2. 在Visual Studio 2019开发使用QQuick时,运行时卡在了setcontextProperty
函数执行时,可能是生成了类图并添加到了了工程(项目)中,删掉或移除多余的文件(类图)即可
3. 在Windows上使用qmake构建带有 Address Sanitizer 的Qt程序:
# # app.pro
include(../win32-clang-msvc/qmake.conf)
# Generate debug information
CONFIG += force_debug_info
# Force release build as debug builds are not supported
CONFIG += release
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -fsanitize=address
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += -fsanitize=address
# # Add the path to the clang ASAN runtime and link against
QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += /LIBPATH:\"C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/Llvm/x64/lib/clang/10.0.0/lib/windows\"
QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += clang_rt.asan_dynamic-x86_64.lib /wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib
//main.cpp
#include <QApplication>
#include <QByteArray>
#include <QDebug>
#include <QTimer>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTimer t;
t.setInterval(0);
t.setSingleShot(true);
{
QByteArray ba = QByteArrayLiteral("Test byte array literal");
t.connect(&t, &QTimer::timeout, &t, [d=ba.data()](){
qDebug() << d;
});
}
t.start();
return app.exec();
}
运行程序,我们会看到如下输出
=================================================================
==15844==ERROR: AddressSanitizer: heap-use-after-free on address 0x12643130a628 at pc 0x7ff81ca3e54a bp 0x00b1e08f86e0 sp 0x00b1e08f8728
READ of size 24 at 0x12643130a628 thread T0
#0 0x7ff81ca3e572 in _asan_wrap_strlen+0x1b2 (C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\lib\clang\10.0.0\lib\windows\clang_rt.asan_dynamic-x86_64.dll+0x18002e572)
#1 0x7ff813417f6e in QString::fromUtf8 C:\qt5\qtbase\src\corelib\tools\qstring.h:572
#2 0x7ff7780318aa in QtPrivate::QFunctorSlotObject<`lambda at C:\test-build-with-sanitized-qt\main.cpp:15:45',0,QtPrivate::List<>,void>::impl C:\qt-build-sanitized\include\QtCore\qobjectdefs_impl.h:439
#3 0x7ff813cd4fc3 in QMetaObject::activate C:\qt5\qtbase\src\corelib\kernel\qobject.cpp:3781
#4 0x7ff813cf1671 in QTimer::timerEvent C:\qt5\qtbase\src\corelib\kernel\qtimer.cpp:255
#5 0x7ff813cbfcf5 in QObject::event C:\qt5\qtbase\src\corelib\kernel\qobject.cpp:1247
#6 0x7ff8158ac7a7 in QApplicationPrivate::notify_helper C:\qt5\qtbase\src\widgets\kernel\qapplication.cpp:3737
#7 0x7ff8158b2470 in QApplication::notify C:\qt5\qtbase\src\widgets\kernel\qapplication.cpp:3598
#8 0x7ff813c19f8d in QCoreApplication::notifyInternal2 C:\qt5\qtbase\src\corelib\kernel\qcoreapplication.cpp:1084
#9 0x7ff813d7ef0d in QEventDispatcherWin32::event C:\qt5\qtbase\src\corelib\kernel\qeventdispatcher_win.cpp:1064
#10 0x7ff8158ac7a7 in QApplicationPrivate::notify_helper C:\qt5\qtbase\src\widgets\kernel\qapplication.cpp:3737
#11 0x7ff8158b2470 in QApplication::notify C:\qt5\qtbase\src\widgets\kernel\qapplication.cpp:3598
#12 0x7ff813c19f8d in QCoreApplication::notifyInternal2 C:\qt5\qtbase\src\corelib\kernel\qcoreapplication.cpp:1084
#13 0x7ff813c1f045 in QCoreApplicationPrivate::sendPostedEvents C:\qt5\qtbase\src\corelib\kernel\qcoreapplication.cpp:1821
#14 0x7ff84512b0b5 in QWindowsGuiEventDispatcher::sendPostedEvents C:\qt5\qtbase\src\platformsupport\eventdispatchers\qwindowsguieventdispatcher.cpp:81
#15 0x7ff813d6fdee in qt_internal_proc C:\qt5\qtbase\src\corelib\kernel\qeventdispatcher_win.cpp:245
#16 0x7ff88793e857 in CallWindowProcW+0x3f7 (C:\WINDOWS\System32\USER32.dll+0x18000e857)
#17 0x7ff88793e298 in DispatchMessageW+0x258 (C:\WINDOWS\System32\USER32.dll+0x18000e298)
#18 0x7ff813d757d5 in QEventDispatcherWin32::processEvents C:\qt5\qtbase\src\corelib\kernel\qeventdispatcher_win.cpp:639
#19 0x7ff84512b046 in QWindowsGuiEventDispatcher::processEvents C:\qt5\qtbase\src\platformsupport\eventdispatchers\qwindowsguieventdispatcher.cpp:74
#20 0x7ff813c0aaaf in QEventLoop::exec C:\qt5\qtbase\src\corelib\kernel\qeventloop.cpp:225
#21 0x7ff813c1bf60 in QCoreApplication::exec C:\qt5\qtbase\src\corelib\kernel\qcoreapplication.cpp:1385
#22 0x7ff778031443 in main C:\test-build-with-sanitized-qt\main.cpp:21
#23 0x7ff7780326b3 in __scrt_common_main_seh D:\agent\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#24 0x7ff888866fd3 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180016fd3)
#25 0x7ff8890fcec0 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18004cec0)
0x12643130a628 is located 24 bytes inside of 48-byte region [0x12643130a610,0x12643130a640)
freed by thread T0 here:
#0 0x7ff81ca45094 in _asan_memmove+0x344 (C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\lib\clang\10.0.0\lib\windows\clang_rt.asan_dynamic-x86_64.dll+0x180035094)
#1 0x7ff77803141f in main C:\test-build-with-sanitized-qt\main.cpp:18
#2 0x7ff7780326b3 in __scrt_common_main_seh D:\agent\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#3 0x7ff888866fd3 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180016fd3)
#4 0x7ff8890fcec0 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18004cec0)
previously allocated by thread T0 here:
#0 0x7ff81ca451a4 in _asan_memmove+0x454 (C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\lib\clang\10.0.0\lib\windows\clang_rt.asan_dynamic-x86_64.dll+0x1800351a4)
#1 0x7ff813503701 in QArrayData::allocate C:\qt5\qtbase\src\corelib\tools\qarraydata.cpp:118
#2 0x7ff81350bcaf in QByteArray::reallocData C:\qt5\qtbase\src\corelib\tools\qbytearray.cpp:1905
#3 0x7ff81341493b in QByteArray::data C:\qt5\qtbase\src\corelib\tools\qbytearray.h:569
#4 0x7ff778031313 in main C:\test-build-with-sanitized-qt\main.cpp:15
#5 0x7ff7780326b3 in __scrt_common_main_seh D:\agent\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#6 0x7ff888866fd3 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180016fd3)
#7 0x7ff8890fcec0 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18004cec0)
SUMMARY: AddressSanitizer: heap-use-after-free (C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\lib\clang\10.0.0\lib\windows\clang_rt.asan_dynamic-x86_64.dll+0x18002e572) in _asan_wrap_strlen+0x1b2
Shadow bytes around the buggy address:
0x04a8b7561470: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
0x04a8b7561480: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
0x04a8b7561490: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x04a8b75614a0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 01 fa
0x04a8b75614b0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 00
=>0x04a8b75614c0: fa fa fd fd fd[fd]fd fd fa fa 00 00 00 00 00 00
0x04a8b75614d0: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x04a8b75614e0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
0x04a8b75614f0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
0x04a8b7561500: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
0x04a8b7561510: fa fa 00 00 00 00 00 04 fa fa 00 00 00 00 00 04
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==15844==ABORTING
4. 在Linux使用qmake构建带有 Address Sanitizer 的Qt程序:
# # application.pro
QT += widgets gui core
TEMPLATE = app
TARGET = application
CONFIG += sanitizer
CONFIG += sanitizer_address
# CONFIG += sanitize_undefined
# CONFIG += sanitize_leak
# CONFIG += sanitize_thread
QMAKE_CXXFLAGS+= -ggdb
SOURCES += main.cpp
5. Qt程序部署后,阴影等特效不起作用,甚至阴影变成黑色背景:
+ 检查屏幕色深:根据官方文档中的说明,屏幕色深低于16-bits的话是特效是不起作用的
+ 如果是在Linux上,查看日志或控制台输出,观察是否有类似
libGL.so.1: unable load to driver: s3g
这样的输出,如有有,请检查显卡驱动,或自己程序发布时是否多带了一下系统的库,将程序多带的libstdc++.so* libX11* libxcb* libGL*都删掉可以解决此问题
6. 为QT应用添加管理员权限
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
7. 下载文件限速:
- 通过QNetworkReply的setReadBufferSize理论上可以实现,但是Qt官方一直没解决这个函数的bug。
- 可以使用QTcpSocket的setReadBufferSize实现,这里暂时没有发现bug(5.9之后)
- **建议使用libcurl实现**, 例如: `curl_easy_setopt (curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) down_speed * 1024);`具体可参考[这篇博客](https://blog.csdn.net/tao_627/article/details/39047253)。
- 基于
QAbstractItemView
(如QTableview、QListview)的item拖拽和多选拖拽,当view->setSelecitonMode(QAbstractItemView::ExtendedSelection);
的选择模式后,我们可以使用Ctrl按键进行多选和反选、也可以拖动多选。但是无法在dragMovEvent
和dropEvent
中使用Qt::ControlModifier
作为拖动复制的控制键。
解决方法:
if (event->modifiers() & Qt::ControlModifier) {
QPoint pos = event->pos();
QPersistentModelIndex index = indexAt(pos);
QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
if (index.isValid()) {
command &= ~QItemSelectionModel::Toggle;
auto ctrlDragSelectionFlag = selectionModel()->isSelected(index)
? QItemSelectionModel::Deselect
: QItemSelectionModel::Select;
command |= ctrlDragSelectionFlag;
// 如果在 setSelectionBehavior()中设置了SelectRows模式
// command |= QItemSelectionModel::Rows;
if( 0 == (command & QItemSelectionModel::Current) )
selection(QRect(pos, Qsize(1, 1)), command);
}
}
继承并重写tableview或listview的mousePressEvent和mouseReleaseEvent,并在这两个函数中分别写入以上代码,再调用父类的函数即可。如:
void MyListView::mousePressEvent(QMouseEvent* event) {
// 调用上述代码
...
QListView::mousePressEvent(event);
}
9. 不同系统下打开文件夹并选定指定的文件
> 参考网址: [stackoverflow](https://stackoverflow.com/questions/13680415/how-to-open-explorer-with-a-specific-file-selected)
+ Windows下比较简单,直接在程序中调用命令行即可。如:
`explorer /select,E:\DevSidecar.zip` , 效果如下所示![在这里插入图片描述](https://img-blog.csdnimg.cn/6bd9917ca737448381ae4a9046ba02d9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATmljZUJsdWVDaGFp,size_20,color_FFFFFF,t_70,g_se,x_16)
- Linux下调用DBus,可先用qdbusviewer工具进行查看
参考网址:freedesktop.org
auto m = QDBusMessage::createMethodCall("org.freedesktop.FileManager1",
"/org/freedesktop/FileManager1",
"org.freedesktop.FileManager1",
"ShowItems");
m << QStringList{ QUrl::fromLocalFile("/home/foo/file1_name").toString(QUrl::FullyEncoded), "file:///home/foo/file2_name" } << "" ;
bool ret = QDBusConnection::sessionBus().send(m); // ret == true
10. 如果想同时在Linux和Windows下第二次用QFile打开续写一个文件,请使用QFile(filePath).open(QIODevice::ReadWrite)
模式打开。
11. Qt程序在Linux (Qtcreator里)下运行默认不显示qDebug打印的日志,可以在启动前设置环境变量QT_LOGGING_RULES=*.debug=true
,可以在新版的QtCreator里看到这个环境变量默认是QT_LOGGING_RULES=*.debug=false
12. 设置环境变量 export QT_DEBUG_PLUGINS=1
可以看到QtCreator等Qt应用加载插件报错的详细信息
13. 如果在程序中对自己的配置文件进行写操作,为防止写入失败,请使用QSaveFile
类进行写入操作,如果有必要,请设置setDirectWriteFallback(true)
,配置文件尽量不用ini文件和xml,请尽量使用JSON文件作为配置文件。
14. Qt-Bug, 复现步骤:
-
环境:Windows10 或 Windows11, 在设置中开启自动隐藏任务栏选项(不隐藏任务栏不会有此bug)
-
Qt版本:
- 5.9.9版本无此bug
- 5.13.x有此bug
- 5.15.x有此bug
- 6.2.0 – 6.2.2有此bug
-
控件: 无边框窗口
-
复现步骤:
- 点击最大化按钮(调用
showMaximized()
, 窗口最大化) - 点击最小化按钮(调用
showMinimized()
, 窗口最小化) - 点击任务栏程序图标,使窗口显示出来
- 点击还原(最大化)按钮 (调用
showNormal()
, 窗口还原) - bug出现: 调用
isMaximized()
判断返回true, 预期返回false
- 点击最大化按钮(调用
问题分析: 通过查看Qt源码和进源码调试,推测可能由修改QTBUG-46763后引起的新bug
#include "widget.h"
#include "ui_widget.h"
#include <QStyle>
#include <QWindow>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
setWindowFlag(Qt::FramelessWindowHint);
connect(ui->btnMin, &QPushButton::clicked, this, &QWidget::showMinimized);
connect(ui->btnQuit, &QPushButton::clicked, this, &QWidget::close);
connect(ui->btnMax, &QPushButton::clicked, this, [this]{
qDebug() << "before"<< windowState() << windowHandle()->windowState();
if (isMaximized()) {
// 去掉这行注释即可解决bug
// windowHandle()->setWindowState(Qt::WindowNoState);
showNormal();
qWarning() << "showNormal";
ui->btnMax->setProperty("isMaxed", false);
} else {
showMaximized();
qWarning() << "showMaximized";
ui->btnMax->setProperty("isMaxed", true);
}
qDebug() << "after"<< windowState() << windowHandle()->windowState();
});
}
Widget::~Widget()
{
delete ui;
}
15. 获取Caps Lock按键状态
#if defined (Q_OS_LINUX)
#include <QX11Info>
#include <X11/Xlib.h>
#define XK_MISCELLANY
#include <X11/keysymdef.h>
#elif defined (Q_OS_WIN)
#include <windows.h>
#include <winuser.h>
#endif
bool getCapsLockToggled()
{
#if defined (Q_OS_LINUX)
auto dpy = QX11Info::display();
XKeyboardState x;
XGetKeyboardControl(dpy, &x);
if (x.led_mask & 0x01)
return true;
else
return false;
#elif defined (Q_OS_WIN)
auto ret = GetKeyState(VK_CAPITAL);
if (ret & 0x01)
return true;
else
return false;
#endif
// TODO: Q_OS_MAC(太穷没见过mac,暂时不写)
}
16. 禁止子进程继承句柄
// 使用场景, 做rotating file log时,如果有子进程,那么日志文件句柄被继承,无法关闭,提示被占用
// 需要在open后禁用子进程继承句柄
FILE* fp = fopen("app.log", "a+");
#if defined(_WIN32)
int fd = _fileno(logfp);
HANDLE handel = _get_osfhandle(fd);
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0x0);
#else // unix
// TODO
#endif
17. deepin(UOS)适配
- 使用
xrdb -query
查询出来的dpi/96.0 就是缩放比例,计算出缩放比例后,在构造QApp对象前设置QT_SCREEN_SCALE_FACTORS=缩放比例
, 不要使用qApp->setAttribute(Qt::AA_EnableHighDpiScaling);
, 会导致窗口不显示,deepin桌面也会自动对应用进行缩放,不计算dpi也可以。 - 系统内置了环境变量
QT_PLUGIN_PATH
,可以通过设置环境变量export QT_DEBUG_PLUGINS=1
观察程序从哪里加载plugins。 - 系统默认启动Qt应用使用的wayland,在启动脚本中添加启动参数
exec yourapp -platform xcb
即可。 - 加载字体需要设置环境变量
export QT_QPA_FONTDIR="$TOPDIR/bin/plugins/fonts"