我有一个最小的应用程序,它使用QOpenGLWidget
集成了 OpenGL 包装库 (OpenSceneGraph)。我试图弄清楚在处理我使用的 OpenGL 内容时如何正确使用 Qt5.6 对高 DPI 屏幕的支持。
My 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();
}
The QtOSGWidget
源自QOpenGLWidget
与 OpenSceneGraph 内容:我使用osgViewer::GraphicsWindowEmbedded
渲染我的简单场景。
为了将 OSG 与 Qt 合并,我重新定义了*GL()
方法:paintGL()
, resizeGL()
and initializeGL()
。我按照 Qt 文档了解每个*GL()
方法应包含,即:
-
paintGL()
确保查看器已更新
-
resizeGL()
确保图形窗口的大小正确调整(连同相机和视口);
-
initializeGL()
确保 OpenGL 状态已初始化。
- 我还重新定义了 Qt 鼠标事件,以便将事件传递给 OSG
当我在正常分辨率屏幕上运行我的示例时,或者使用QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
,场景看起来应该是:
此外,当我操纵相机视图时,鼠标坐标会被正确捕获。
但是,当我设置高 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()
功能。