You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双显示器环境下Qt/QML中Unity子窗口位置设置异常排查

问题分析与修复方案

问题根源

你的问题出在多显示器DPI缩放不匹配上:

  • 笔记本主屏(1920×1080)的DPI缩放比例为100%,而4K副屏的缩放比例大概率是150%或200%(从日志窗口尺寸差值可推断:4K屏窗口矩形与客户区的差值远大于主屏,对应更高的DPI缩放等级)。
  • QML中frame.x和frame.y是逻辑坐标(已适配系统DPI),但Windows API的MoveWindow接收的是物理像素坐标(真实屏幕像素),直接传递逻辑坐标会导致位置偏移。

验证依据

从日志对比可明确差异:

  • 主屏(100%缩放):QML窗口尺寸1920×1017与客户区物理尺寸完全一致,逻辑坐标等于物理坐标,因此MoveWindow定位正常。
  • 4K屏(高DPI缩放):QML窗口尺寸2560×1377是逻辑尺寸,客户区物理尺寸为3840×2066(2560×1.5=3840,1377×1.5≈2066),说明系统DPI缩放比例为150%,但你直接将逻辑坐标384、137传给MoveWindow,实际物理位置仅为预期位置的1/1.5,自然出现偏移。

修复步骤

需要将QML传递的逻辑坐标转换为Windows物理像素坐标,具体实现如下:

1. 获取窗口所在显示器的DPI缩放比例

在printWindowParameters函数中添加代码,获取当前窗口对应的显示器DPI:

void printWindowParameters(int target_x, int target_y){
    // 新增:获取显示器DPI缩放比例
    HMONITOR hMonitor = MonitorFromWindow((HWND)mainWindowID, MONITOR_DEFAULTTONEAREST);
    UINT dpiX, dpiY;
    GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
    qreal scaleX = dpiX / 96.0;
    qreal scaleY = dpiY / 96.0;

    // 原有代码...
    RECT window_rectangle, client_rectangle;
    GetWindowRect((HWND) mainWindowID, &window_rectangle);
    GetClientRect((HWND) mainWindowID, &client_rectangle);
    
    qint32 wh = window_rectangle.bottom - window_rectangle.top;
    qint32 ww = window_rectangle.right - window_rectangle.left;
    qint32 ch = client_rectangle.bottom - client_rectangle.top;
    qint32 cw = client_rectangle.right - client_rectangle.left;
    qint32 dW = ww - cw;
    qint32 dH = wh - ch;
    
    if ((dW < 0) || (dH < 0)) return;
    
    qDebug() << "Window Rectangle: (" << window_rectangle.left << "," << window_rectangle.top << ")" << ww << "x" << wh;
    qDebug() << "Client Rectangle: (" << client_rectangle.left << "," << client_rectangle.top << ")" << cw << "x" << ch;
    qDebug() << "Win - Client. H:" << dH << ". W" << dW << ". Target Coordinates (" << target_x << "," << target_y << ")";
    qDebug() << "DPI Scale: " << scaleX << "x" << scaleY;

    // 2. 转换逻辑坐标为物理像素坐标
    qint32 physicalX = qRound(target_x * scaleX);
    qint32 physicalY = qRound(target_y * scaleY);
    qint32 h = 300;
    qint32 w = 300;
    
    qDebug() << "Setting inner window to (" << physicalX << "," << physicalY << ")" << w << "x" << h;
    
    MoveWindow(child_window_handle, physicalX, physicalY, w, h, TRUE);
}

2. 确保Qt应用启用高DPI支持

在Qt应用的main函数开头添加高DPI配置,避免Qt自身坐标系统混乱:

#include <QApplication>

int main(int argc, char *argv[])
{
    // 启用Qt高DPI缩放支持
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
    
    QApplication app(argc, argv);
    // ... 原有初始化代码
    return app.exec();
}

补充说明

  • 若Unity子窗口出现内容模糊或尺寸异常,需在Unity项目的Player Settings中开启Enable High DPI Mode,确保子窗口适配高DPI环境。
  • 若使用Qt 6,高DPI支持默认已启用,但仍需确认窗口的DPI感知设置正确。

内容的提问来源于stack exchange,提问作者aarelovich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 09:20:31