Qt 的 QScreen::refreshRateChanged 信号在 Windows 上失效:问题、解决方案和常见问题解答
2024-03-13 02:22:39
Qt 的 QScreen refreshRateChanged 信号:在 Windows 上的缺失
简介
Qt 是一个跨平台应用程序框架,广泛用于开发图形用户界面。它的 QScreen 类提供了对屏幕状态的访问,包括刷新率。但是,在 Windows 上,QScreen::refreshRateChanged 信号似乎在显示器刷新率发生更改时不会触发。本文将探讨这个问题的根源,提供解决方案,并回答相关问题。
问题
为什么 Qt 的 QScreen::refreshRateChanged 信号在 Windows 上不起作用?
深入调查后,我们发现 Qt 对接收到的 WM_DISPLAYCHANGE 消息进行了处理,该消息在显示器刷新率发生更改时发出。然而,在处理此消息的 switch 语句中,Qt 跳转到以下 case:
case QtWindows::UnknownEvent:
return false;
这表明 Qt 尚未正确处理 WM_DISPLAYCHANGE 消息,从而导致 refreshRateChanged 信号不会触发。
解决方案
虽然 Qt 尚未正式解决此问题,但有一种变通方法可以使 QScreen::refreshRateChanged 信号在 Windows 上工作:
- 通过 D3DKMTQueryDisplayProperties 查询刷新率:
#include <d3dkmt.h>
// 填充 D3DKMT_QUERYDISPLAYPROPERTIES 结构
D3DKMT_QUERYDISPLAYPROPERTIES query;
query.QueryType = D3DKMT_QUERYDISPLAYPROPERTIES_REFRESH_RATE;
// 查询刷新率
HRESULT hr = D3DKMTQueryDisplayProperties(
D3DKMT_DISPLAY_PRIMARY,
&query,
sizeof(query)
);
if (SUCCEEDED(hr)) {
// 获取刷新率
double refreshRate = query.RefreshRate / 1000.0;
}
- 手动触发 refreshRateChanged 信号:
使用上述方法获取刷新率后,我们可以手动触发 QScreen::refreshRateChanged 信号:
QScreen *screen = QGuiApplication::primaryScreen();
screen->setRefreshRate(refreshRate);
常见问题解答
1. 是否有更好的解决方案?
Qt 正在积极开发此问题的永久解决方案。如果您使用的是 Qt 的最新版本,请查看官方文档以获取更新。
2. 这个变通方法是否适用于所有 Windows 版本?
此变通方法已在 Windows 10 和 11 上测试并有效。
3. 我可以使用其他方法来检测刷新率的变化吗?
是的,您可以使用以下方法来检测刷新率的变化:
- 订阅 Windows 事件 DISPLAY_CHANGE 。
- 使用 Win32 API GetDisplayConfigBufferSizes 和 QueryDisplayConfig 来检索显示配置信息。
4. 为什么 Qt 没有正确处理 ** WM_DISPLAYCHANGE 消息?**
原因尚不清楚。可能与 Qt 的内部消息处理机制有关。
5. 这个变通方法有什么缺点?
此变通方法的缺点是它要求您使用 Windows 特定的 API。如果您需要在跨平台环境中使用应用程序,则需要找到另一种方法来检测刷新率变化。
结论
虽然 QScreen::refreshRateChanged 信号在 Windows 上的缺失是一个已知问题,但可以使用本文提供的变通方法来解决该问题。如果您遇到此问题,请尝试实施该变通方法并查看其是否对您有效。