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
是从QOpenGLWidget
派生的,具有OpenSceneGraph内容:我使用osgViewer :: GraphicsWindowEmbedded
来渲染我的简单场景。
为了将OSG与Qt合并,我重新定义了*GL()
方法:paintGL()
、resizeGL()
和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的回答,我找到了缩放的解决方案。首先,我需要知道X和Y维度中DPI的一些参考值。然后,我基于此计算缩放坐标,并将它们传递给我的widget
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()
函数,更加合理。