Qt5.6:高 DPI 支持和 OpenGL (OpenSceneGraph)
Qt5.6: high DPI support and OpenGL (OpenSceneGraph)
我有一个最小的应用程序,它使用 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()
确保图形 window 正确调整大小(连同相机和视口);
initializeGL()
确保 OpenGL 状态已初始化。
- 我还重新定义了 Qt 鼠标事件,以便将事件传递给 OSG
当我 运行 我的示例在正常分辨率屏幕上,或使用 QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
时,场景看起来应该是:
此外,当我操纵相机视图时,鼠标坐标被正确捕获。
然而,当我设置高 DPI 选项时,这是我得到的:
事件的鼠标坐标也被缩放并且没有正确传递到 OpenSceneGraph 的事件处理程序。
如您所见,图形 window 大小未由 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()
?或者正确的处理方法是什么?
Update/Solution 使用手动缩放:感谢@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()
函数。
Is there a way to know to what size the scaling will be performed so
that to do resizeGL()
correctly?
首先检测显示器:
// 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);
从中可以看出很多屏幕特性,包括"physical dot per inch"可以判断每英寸有多少像素:
qreal pxPerInch = pScreen->physicalDotsPerInch();
有了每英寸的像素,您将能够以编程方式缩放您的绘图代码。检测 'normal' 密度是多少,然后根据物理设备上检测到的密度按比例缩放。当然,这种方法更适合精确的图形。不过,请注意这两个 physicalDotPerInch() and devicePixelRatio()。
qreal scaleFactor = pScreen->physicalDotsPerInch() / normalPxPerInch;
Or what is the correct way to deal with the problem?
然而,使用小部件和普通 GUI 绘图通常更容易让 Qt/系统缩放整个 UI。 Qt 文档:High DPI Displays.
如果 OS Windows 至少是 Vista 或更高版本,并且为高 DPI 调整 Qt 听起来很复杂,那么我有一个捷径可以帮助我,尽管 Qt 在日志中抱怨: "SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)"
“。我在事件循环之前从 main()
调用此函数:SetProcessDPIAware() and then all the UI looks alike no matter what monitor density is. I use it with Qt 5.5, though. There is also SetProcessDpiAwareness() 函数,探索。我使用 SetProcessDPIAware
因为它自 Windows Vista 以来可用,但 SetProcessDpiAwareness
仅在 Windows 8.1 之后可用。因此,决定可能取决于潜在的客户系统。
一个'shortcut'方法:
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();
}
我有一个最小的应用程序,它使用 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()
确保图形 window 正确调整大小(连同相机和视口);initializeGL()
确保 OpenGL 状态已初始化。- 我还重新定义了 Qt 鼠标事件,以便将事件传递给 OSG
当我 运行 我的示例在正常分辨率屏幕上,或使用 QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
时,场景看起来应该是:
此外,当我操纵相机视图时,鼠标坐标被正确捕获。
然而,当我设置高 DPI 选项时,这是我得到的:
事件的鼠标坐标也被缩放并且没有正确传递到 OpenSceneGraph 的事件处理程序。
如您所见,图形 window 大小未由 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()
?或者正确的处理方法是什么?
Update/Solution 使用手动缩放:感谢@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()
函数。
Is there a way to know to what size the scaling will be performed so that to do
resizeGL()
correctly?
首先检测显示器:
// 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);
从中可以看出很多屏幕特性,包括"physical dot per inch"可以判断每英寸有多少像素:
qreal pxPerInch = pScreen->physicalDotsPerInch();
有了每英寸的像素,您将能够以编程方式缩放您的绘图代码。检测 'normal' 密度是多少,然后根据物理设备上检测到的密度按比例缩放。当然,这种方法更适合精确的图形。不过,请注意这两个 physicalDotPerInch() and devicePixelRatio()。
qreal scaleFactor = pScreen->physicalDotsPerInch() / normalPxPerInch;
Or what is the correct way to deal with the problem?
然而,使用小部件和普通 GUI 绘图通常更容易让 Qt/系统缩放整个 UI。 Qt 文档:High DPI Displays.
如果 OS Windows 至少是 Vista 或更高版本,并且为高 DPI 调整 Qt 听起来很复杂,那么我有一个捷径可以帮助我,尽管 Qt 在日志中抱怨: "SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)"
“。我在事件循环之前从 main()
调用此函数:SetProcessDPIAware() and then all the UI looks alike no matter what monitor density is. I use it with Qt 5.5, though. There is also SetProcessDpiAwareness() 函数,探索。我使用 SetProcessDPIAware
因为它自 Windows Vista 以来可用,但 SetProcessDpiAwareness
仅在 Windows 8.1 之后可用。因此,决定可能取决于潜在的客户系统。
一个'shortcut'方法:
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();
}