6

我有一个最小的应用程序,它使用QOpenGLWidget集成了 OpenGL 包装库(OpenSceneGraph)。我试图弄清楚在处理我使用的 OpenGL 内容时如何正确使用 Qt5.6 对高 DPI 屏幕的支持。

我的main()函数有以下代码:

int main(int argc, char** argv)
{
    // DPI support is on
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);
    QMainWindow window;

    // QOpenGLWidget with OpenSceneGraph content
    QtOSGWidget* widget = new QtOSGWidget();

    window.setCentralWidget(widget);
    window.show();
    return app.exec();
}

QtOSGWidget源自QOpenGLWidgetOpenSceneGraph 内容:我osgViewer::GraphicsWindowEmbedded用来渲染我的简单场景。

为了将 OSG 与 Qt 合并,我重新定义了*GL()方法paintGL()resizeGL()initializeGL(). 我按照 Qt 文档了解每种*GL()方法应包含的内容,即:

  • paintGL()确保查看器已更新
  • resizeGL()确保正确调整图形窗口的大小(连同相机和视口);
  • initializeGL()确保 OpenGL 状态已初始化。
  • 我还重新定义了 Qt 鼠标事件,以便将事件传递给 OSG

当我在普通分辨率屏幕上运行我的示例时,或者使用QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);时,场景看起来应该:

圆柱体示例 - 高 DPI 支持已关闭

此外,当我操纵相机视图时,鼠标坐标被正确捕获。

但是,当我设置高 DPI 选项时,这就是我得到的:

高 DPI 已开启

事件的鼠标坐标也被缩放,并且没有正确传递给 OpenSceneGraph 的事件处理程序。

如您所见,图形窗口大小不是由 Qt 缩放的。这可能是因为我设置尺寸的方式:

virtual void resizeGL( int width, int height ) 
{
    // resize event is passed to OSG
    this->getEventQueue()->windowResize(this->x(), this->y(), width, height);

    // graphics window resize
    m_graphicsWindow->resized(this->x(), this->y(), width, height);

    // camera viewport
    osg::Camera* camera = m_viewer->getCamera();
    camera->setViewport(0, 0, this->width(), this->height());
}

Qt 不会按比例缩放该大小。鼠标事件坐标也会发生同样的事情。

我的问题:有没有办法知道将执行缩放的大小以便resizeGL()正确执行?或者解决问题的正确方法是什么?

使用手动缩放更新/解决方案:感谢@AlexanderVX 的回答,我找到了缩放解决方案。首先,我需要知道一些 DPI 在 X 和 Y 维度上的参考值。然后我根据它计算缩放坐标并将它们传递给我的小部件QtOSGWidget。因此,代码main()必须包含:

QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);

int x = QApplication::desktop()->physicalDpiX();
int y = QApplication::desktop()->physicalDpiY();
// values 284 and 285 are the reference values
double scaleX = 284.0/double(x);
double scaleY = 285.0/double(y);

QMainWindow window;
QtOSGWidget* widget = new QtOSGWidget(scaleX, scaleY, &window);
// etc.

然后,每当我提到需要传递给 OpenSceneGraph (OpenGL) 内容的大小调整函数时,我都必须进行缩放,例如:

// resizeGL example
this->getEventQueue()->windowResize(this->x()*m_scaleX, this->y() * m_scaleY, width*m_scaleX, height*m_scaleY);

// mouse event example
this->getEventQueue()->mouseButtonPress(event->x()*m_scaleX, event->y()*m_scaleY, button);

最终更新:由于我的应用程序的目标平台是 Windows 7-10,因此坚持@AlexanderV(第二部分)提出的答案更有意义,即使用SetProcessDPIAware()函数。

4

1 回答 1

4

有没有办法知道将执行缩放的大小以便resizeGL()正确执行?

首先,检测监视器:

        // relative to widget
        int screenNum = QApplication::desktop()->screenNumber(pWidget);

或者可能

        // relative to global screen position
        int screenNum = QApplication::desktop()->screenNumber(pWidget->topLeft());

这给了我们指向QScreen

        QScreen* pScreen = QApplication::desktop()->screen(screenNum);

您可以从中读取许多屏幕特征,包括“每英寸物理点”,这使我们能够判断每英寸有多少像素:

        qreal pxPerInch = pScreen->physicalDotsPerInch();

拥有每英寸像素,您将能够以编程方式缩放您的绘图代码。检测多少是“正常”密度,然后根据物理设备上检测到的密度按比例缩放。当然,这种方法更适合精确的图形。不过,请注意physicalDotPerInch()devicePixelRatio()

        qreal scaleFactor = pScreen->physicalDotsPerInch() / normalPxPerInch;

或者解决问题的正确方法是什么?

然而,使用小部件和普通的 GUI 绘图通常更容易让 Qt / 系统缩放整个 UI。Qt 文档:高 DPI 显示

如果操作系统 Windows 至少为 Vista 或更高版本并为高 DPI 调整 Qt 听起来很复杂,那么我有一个捷径可以帮助我,尽管 Qt 在日志中抱怨: “。我 在事件循环之前"SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)" 调用这个函数: SetProcessDPIAware ()然后无论显示器密度如何,所有 UI 看起来都一样。不过,我将它与 Qt 5.5 一起使用。还有SetProcessDpiAwareness()函数,探索。我使用它是因为它从 Windows Vista 开始可用,但仅从 Windows 开始可用8.1. 因此,决定可能取决于潜在的客户系统。main()SetProcessDPIAwareSetProcessDpiAwareness

“捷径”方法:

int main(int argc, char** argv)
{
    // DPI support is on
    // QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

     // on Windows?
    ::SetProcessDPIAware();
    // MSDN suggests not to use SetProcessDPIAware() as it is obsolete and may not be available.
    // But it works with widgets.

    QApplication app(argc, argv);
    QMainWindow window;

    // QOpenGLWidget with OpenSceneGraph content
    QtOSGWidget* widget = new QtOSGWidget();

    window.setCentralWidget(widget);
    window.show();
    return app.exec();
}
于 2016-05-18T16:13:14.323 回答