一、Qt Widgets 问题交流
1.
二、Qt Quick 问题交流
1.Qt5.15非动态创建的子窗口onCompleted时调用show不显示
测试环境:Qt5.15.2 + MSVC2019/2022+Windows10/11
如测试代码所示:子窗口直接show无法显示,需要设置visible=true,或者动态创建子窗口
测试代码:
javascript
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
id: root
width: 640
height: 480
visible: true
title: qsTr("Root")
Window {
id: sub1
width: 400
height: 300
title: qsTr("Sub1")
}
Component {
id: comp2
Window {
id: sub2
width: 400
height: 300
title: qsTr("Sub2")
}
}
Component.onCompleted: {
// Qt5初始化的时候子窗口就show,会自动关闭,设置visible后就不会
sub1.show()
// sub1.visible = true
// 动态创建并show可以正常显示
// let obj = comp2.createObject(root)
// obj.show()
}
}
三、其他
1.在QtConcurrent::run抛出std异常的捕获问题
如果QtConcurrent::run返回的QFuture用Qt6的链式接口onFailed捕获异常,当run中抛出std异常时,用QException或者std::exception是获取不到异常内容的,需要用QUnhandledException。
run的实现中对于非QException异常,包装成了QUnhandledException再抛出去,原始的异常信息作为QUnhandledException的成员数据,直接用QException/std::exception自然拿不到具体的异常信息了。
cpp
void run() override
{
if (promise.isCanceled()) {
promise.reportFinished();
return;
}
#ifndef QT_NO_EXCEPTIONS
try {
#endif
runFunctor();
#ifndef QT_NO_EXCEPTIONS
} catch (QException &e) {
promise.reportException(e);
} catch (...) {
promise.reportException(QUnhandledException(std::current_exception()));
}
#endif
promise.reportFinished();
}
测试代码:
cpp
QFuture<void> future = QtConcurrent::run([](){
qDebug() << "doing" << QThread::currentThread();
throw std::runtime_error("err");
QThread::sleep(1);
});
future.cancel();
future.then([] {
qDebug() << "then" << QThread::currentThread();
QThread::sleep(1);
}).onFailed([](const std::runtime_error &e) {
qWarning() << "failed runtime_error" << e.what() << QThread::currentThread();
}).onFailed([](const QUnhandledException &e) {
try {
std::rethrow_exception(e.exception());
}
catch (const std::exception &ex) {
qDebug() << "QUnhandledException" << ex.what() << QThread::currentThread();
}
// qWarning() << "failed QException" << e.what() << QThread::currentThread();
}).onFailed([](const std::exception &e) {
qWarning() << "failed exception" << e.what() << QThread::currentThread();
}).onCanceled([] {
qWarning() << "canceled" << QThread::currentThread();
}).then([] {
// 第一个future逻辑结束后会进入后续的then
// Qt6.10 future提供了cancelChain取消整个链
qDebug() << "then 2" << QThread::currentThread();
});
// future.cancel();
2.Windows上窗口置前问题
直接调用 SetForegroundWindow 只会在任务栏闪烁,并没有将非当前活跃的窗口置前;使用 SetWindowPos 切换 HWND_TOPMOST 状态也只是窗口置前,任务栏上的当前窗口还是没有切换过来的。
参考解决方法:https://www.cnblogs.com/xuhuajie/p/14782205.html
相关文档:https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow
想要 SetForegroundWindow 生效,必须得是前置的进程(活动的进程),可以用以下方法实现:
cpp
// 跨进程SetForegroundWindow 会失效,需要如下代码搞一搞。
HWND hForeWnd = ::GetForegroundWindow();
DWORD dwCurID = ::GetCurrentThreadId();
DWORD dwForeID = ::GetWindowThreadProcessId(hForeWnd, NULL);
::AttachThreadInput(dwCurID, dwForeID, TRUE);
::ShowWindow(m_hWnd, SW_SHOWNORMAL);
::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
::SetForegroundWindow(m_hWnd);
::BringWindowToTop(m_hWnd);
::AttachThreadInput(dwCurID, dwForeID, FALSE);