我有一个使用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状态。当我在普通分辨率屏幕或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参考值。然后我根据它计算缩放坐标并将它们传递给我的小部件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的建议答案(第二部分)更有意义,即使用{ {1}}功能。
答案 0 :(得分:3)
有没有办法知道缩放将执行的大小 要正确地做
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 / system扩展整个UI。 Qt文档:High DPI Displays。
如果操作系统Windows至少Vista或更高版本并且调高Qt以获得高DPI听起来很复杂,那么我会采用一种快捷方式来帮助我,尽管Qt在日志中抱怨:"SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)"
“。我在事件循环之前从main()
调用此函数:SetProcessDPIAware()然后无论显示器密度是多少,所有UI都看起来都很相似。但我在Qt 5.5中使用它。还有{{{ 3}} function,explore。我使用SetProcessDPIAware
因为它自Windows Vista起可用,但SetProcessDpiAwareness
仅在Windows 8.1之后可用。所以,决定可能取决于潜在的客户系统。
'捷径'方法:
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();
}