Qt5.6:高DPI支持和OpenGL(OpenSceneGraph) [英] Qt5.6: high DPI support and OpenGL (OpenSceneGraph)

查看:190
本文介绍了Qt5.6:高DPI支持和OpenGL(OpenSceneGraph)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个最小的应用程序,它使用QOpenGLWidget集成了OpenGL包装器库(OpenSceneGraph).我试图弄清楚在像我使用的那样处理OpenGL内容时如何正确使用Qt5.6对高DPI屏幕的支持.

I have a minimal application which uses QOpenGLWidget that integrates an OpenGL wrapper library (OpenSceneGraph). I am trying to figure out how to correctly use the Qt5.6 support for high DPI screens when dealing with OpenGL content like I use.

我的main()函数具有以下代码:

My main() function has the following code:

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源自具有OpenSceneGraph内容的QOpenGLWidget:我使用osgViewer::GraphicsWindowEmbedded渲染我的简单场景.

The QtOSGWidget is derived from QOpenGLWidget with OpenSceneGraph content: I use osgViewer::GraphicsWindowEmbedded to render my simple scene.

要将OSG与Qt合并,我重新定义了*GL()方法:paintGL()resizeGL()initializeGL().我按照Qt文档了解每个*GL()方法应包含的内容,即:

To merge OSG with Qt, I re-define the *GL() methods: paintGL(), resizeGL() and initializeGL(). I follow the Qt docs on what each of the *GL() methods should contain, i.e.:

  • paintGL()确保查看器已更新
  • resizeGL()确保适当调整图形窗口的大小(以及相机和视口);
  • initializeGL()确保OpenGL状态已初始化.
  • 我还重新定义了Qt鼠标事件,以便将事件传递给OSG
  • paintGL() makes sure the viewer is updated
  • resizeGL() makes sure the graphics window is resized properly (together with camera and viewport);
  • initializeGL() makes sure OpenGL state is initialized.
  • I also re-defined Qt mouse events so that to pass the events to OSG

当我在普通分辨率屏幕上或使用QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);运行示例时,场景看起来应该像这样:

When I run my example on normal resolution screen, or with QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);, the scene looks like it should:

此外,当我操纵摄像机视图时,鼠标坐标会正确捕获.

Also, when I manipulate the camera view, the mouse coordinates are captured correctly.

但是,当我设置高DPI选项时,这就是我得到的:

However, when I set the high DPI option on, this is what I get:

事件的鼠标坐标也会被缩放,并且不会正确传递给OpenSceneGraph的事件处理程序.

The mouse coordinates for events are scaled as well and not passed to the OpenSceneGraph's event handler correctly.

如您所见,图形窗口的大小未按Qt缩放.可能是因为我设置尺寸的方式:

As you can see, the graphics window size is not scaled by Qt. It is probably because of the way how I set up the sizing:

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缩放.鼠标事件坐标也发生同样的事情.

That sizing is not scaled by Qt. Same thing happens to the mouse events coordinates.

我的问题:是否有办法知道要执行多大比例缩放才能正确执行resizeGL()?还是解决问题的正确方法是什么?

My question: is there a way to know to what size the scaling will be performed so that to do resizeGL() correctly? Or what is the correct way to deal with the problem?

使用手动缩放进行更新/解决方案:由于@AlexanderVX的回答,我找到了缩放解决方案.首先,我需要了解X和Y维度上DPI的一些参考值.然后,我据此计算缩放坐标,并将其传递给我的小部件QtOSGWidget.因此,main()的代码必须包含:

Update/Solution using scaling by hand: thanks to the answer of @AlexanderVX, I figured out the scaling solution. At first, I need to know some reference values of DPI in X and Y dimensions. Then I calculate the scaling coordinates based on that and pass them to my widget QtOSGWidget. So, the code of the main() has to contain:

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)内容的大小调整功能时,我都必须进行缩放,例如:

Then, whenever I refer to the sizing functions that needed to be passed to OpenSceneGraph (OpenGL) content, I have to do scaling, e.g.:

// 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()函数.

Final update: since the target platform of my application is Windows 7-10, it makes much more sense to stick with the proposed answer of @AlexanderV (second part), i.e., to use SetProcessDPIAware() function.

推荐答案

是否有一种方法知道执行缩放的大小,因此 正确执行resizeGL()?

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的指针:

and that gives us pointer to QScreen:

        QScreen* pScreen = QApplication::desktop()->screen(screenNum);

您可以从中读取许多屏幕特征,包括每英寸的物理点",它使我们能够判断每英寸有多少像素:

from which you can read many screen characteristics, including "physical dot per inch" which makes us able to judge how many pixels there per inch:

        qreal pxPerInch = pScreen->physicalDotsPerInch();

每英寸具有像素,您将能够以编程方式缩放绘图代码.检测多少是正常"密度,然后与在物理设备上检测到的密度成比例地缩放.当然,这种方法更适合于精确的图形.请注意 physicalDotPerInch() devicePixelRatio().

Having pixels per inch you will be able to programmatically scale your drawing code. Detect how much is 'normal' density and then scale proportionally against the density detected on physical device. Of course that approach is more suitable for accurate graphics. Be aware of both physicalDotPerInch() and devicePixelRatio(), though.

        qreal scaleFactor = pScreen->physicalDotsPerInch() / normalPxPerInch;

或者解决问题的正确方法是什么?

Or what is the correct way to deal with the problem?

但是,使用窗口小部件和普通的GUI绘图,通常让Qt/system缩放整个UI更加容易. Qt文档:高DPI显示.

However, with widgets and normal GUI drawing it is often easier to let Qt / system to scale the entire UI. Qt Documentation: High DPI Displays.

如果OS Windows至少为Vista或更高版本,并且为高DPI调整Qt听起来很复杂,那么尽管Qt在日志中抱怨,但我还是采取了一条捷径并且对我有帮助:"SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)" .我在事件循环之前从main()调用此函数: SetProcessDpiAwareness()函数,请进行探索.我使用SetProcessDPIAware是因为它自Windows Vista以来可用,但SetProcessDpiAwareness仅从Windows 8.1起可用.因此,该决定可能取决于潜在的客户端系统.

If the OS Windows at least Vista or higher and tuning Qt for high DPI sounds complicated then there is a shortcut that I take and it helps me, though Qt complains in the log: "SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)" ". I call this function from main() before the event loop: 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() function, explore. I use SetProcessDPIAware because it is available since Windows Vista but SetProcessDpiAwareness is only available since Windows 8.1. So, the decision may depend on potential clients systems.

一种捷径"方法:

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();
}

这篇关于Qt5.6:高DPI支持和OpenGL(OpenSceneGraph)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆