返回

Qt 的 QScreen::refreshRateChanged 信号在 Windows 上失效:问题、解决方案和常见问题解答

windows

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 上工作:

  1. 通过 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;
}
  1. 手动触发 refreshRateChanged 信号:

使用上述方法获取刷新率后,我们可以手动触发 QScreen::refreshRateChanged 信号:

QScreen *screen = QGuiApplication::primaryScreen();
screen->setRefreshRate(refreshRate);

常见问题解答

1. 是否有更好的解决方案?

Qt 正在积极开发此问题的永久解决方案。如果您使用的是 Qt 的最新版本,请查看官方文档以获取更新。

2. 这个变通方法是否适用于所有 Windows 版本?

此变通方法已在 Windows 10 和 11 上测试并有效。

3. 我可以使用其他方法来检测刷新率的变化吗?

是的,您可以使用以下方法来检测刷新率的变化:

  • 订阅 Windows 事件 DISPLAY_CHANGE
  • 使用 Win32 API GetDisplayConfigBufferSizesQueryDisplayConfig 来检索显示配置信息。

4. 为什么 Qt 没有正确处理 ** WM_DISPLAYCHANGE 消息?**

原因尚不清楚。可能与 Qt 的内部消息处理机制有关。

5. 这个变通方法有什么缺点?

此变通方法的缺点是它要求您使用 Windows 特定的 API。如果您需要在跨平台环境中使用应用程序,则需要找到另一种方法来检测刷新率变化。

结论

虽然 QScreen::refreshRateChanged 信号在 Windows 上的缺失是一个已知问题,但可以使用本文提供的变通方法来解决该问题。如果您遇到此问题,请尝试实施该变通方法并查看其是否对您有效。