vic*_*ann 6 opengl qt dpi openscenegraph qt5.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();
}
Run Code Online (Sandbox Code Playgroud)
将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());
}
Run Code Online (Sandbox Code Playgroud)
该大小不是由 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.
Run Code Online (Sandbox Code Playgroud)
然后,每当我提到需要传递给 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);
Run Code Online (Sandbox Code Playgroud)
最终更新:由于我的应用程序的目标平台是 Windows 7-10,所以坚持@AlexanderV(第二部分)的建议答案更有意义,即使用SetProcessDPIAware()函数。
有没有办法知道缩放将执行到什么尺寸以便
resizeGL()正确执行?
首先,检测显示器:
// relative to widget
int screenNum = QApplication::desktop()->screenNumber(pWidget);
Run Code Online (Sandbox Code Playgroud)
或者可能
// relative to global screen position
int screenNum = QApplication::desktop()->screenNumber(pWidget->topLeft());
Run Code Online (Sandbox Code Playgroud)
这给了我们指向QScreen:
QScreen* pScreen = QApplication::desktop()->screen(screenNum);
Run Code Online (Sandbox Code Playgroud)
从中您可以读取许多屏幕特征,包括“每英寸物理点”,这使我们能够判断每英寸有多少像素:
qreal pxPerInch = pScreen->physicalDotsPerInch();
Run Code Online (Sandbox Code Playgroud)
有了每英寸像素,您将能够以编程方式缩放绘图代码。检测“正常”密度是多少,然后根据物理设备上检测到的密度按比例缩放。当然这种方法更适合精确的图形。不过,请注意physicalDotPerInch()和devicePixelRatio()。
qreal scaleFactor = pScreen->physicalDotsPerInch() / normalPxPerInch;
Run Code Online (Sandbox Code Playgroud)
或者说处理问题的正确方法是什么?
然而,通过小部件和普通的 GUI 绘图,通常更容易让 Qt/系统缩放整个 UI。Qt 文档:高 DPI 显示器。
如果操作系统 Windows 至少为 Vista 或更高版本,并且调整 Qt 以实现高 DPI 听起来很复杂,那么我采用了一个快捷方式,它对我有帮助,尽管 Qt 在日志中抱怨:"SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)"
“。我在事件循环之前调用此函数main() :SetProcessDPIAware ()然后无论显示器密度如何,所有 UI 看起来都一样。不过,我将它与 Qt 5.5 一起使用。还有SetProcessDpiAwareness()函数,探索。我使用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();
}
Run Code Online (Sandbox Code Playgroud)