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.
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();
}
The QtOSGWidget
is derived from QOpenGLWidget
with OpenSceneGraph content: I use osgViewer::GraphicsWindowEmbedded
to render my simple scene.
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()
makes sure the viewer is updatedresizeGL()
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
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.
However, when I set the high DPI option on, this is what I get:
The mouse coordinates for events are scaled as well and not passed to the OpenSceneGraph's event handler correctly.
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());
}
That sizing is not scaled by Qt. Same thing happens to the mouse events coordinates.
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?
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.
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);
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.