QGraphicsView scaling with High DPI - c++

I have an application with QMainWindow in which I insert my own widget, inherited from QGraphicsView. As viewport I use QGLWidget. Everything works fine but with Hidh DPI there is a problem: my widget(inherited from QGraphicsView) is very small.
Before creation of QApplication I enable High DPI support by
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
and in my widget I do following (from signal that comes from QMainWindow deep in the code):
void MyWidget::onNeedResize(QRect newGeom)
{
// some logic, that not interact with GUI stuff
setGeometry(newGeom);
setSceneRect(QRect(QPoint(0, 0), newGeom.size()));
// more logic, that not interact with GUI stuff
}
What did I missed? Where is a problem?
UPD1: I replaced QGLWidget by QOpenGLWidget and everything started work just as expected! Without any modifications/calculations/additional stuff. Setting of the flag is enough. But the problem is I can't use QOpenGLWidget instead of QGLWidget for now.

My assumption on why the dpi scaling does not work is because you use OpenGL widget as your viewport. From Qt docs:
Applications mostly work with device independent pixels. Notable exceptions are OpenGL and code that works with raster graphics.
From that document, it means that OpenGL-content widgets will not be scaled even if you use Qt::AA_EnableHighDpiScaling.
Try to use devicePixelRatio() directly in your resizing code. An example on how it can be used within your code:
void MyWidget::onNeedResize(QRect newGeom)
{
// some logic, that not interact with GUI stuff
setGeometry(QRect(newGeom.x() * Application::desktop()->devicePixelRatio(),
newGeom.y() * Application::desktop()->devicePixelRatio(),
newGeom.width() * Application::desktop()->devicePixelRatio(),
newGeom.height() * Application::desktop()->devicePixelRatio() ));
setSceneRect(QRect(QPoint(0, 0), QSize(
newGeom.width() * Application::desktop()->devicePixelRatio(),
newGeom.height() * Application::desktop()->devicePixelRatio() ) ));
// more logic, that not interact with GUI stuff
}
That is, for every sizing/position you use within your widget, use a scaling factor of Application::desktop()->devicePixelRatio(). That should fix your problem.

Related

Can QOpenGLWidget be integrated with third party OpenGL library?

Legacy QGLWidget could be integrated with rendering libraries (like SFML) by passing winId() result to the rendering library. But I can't make QOpenGLWidget work that way. After making it MainWindow's central widget I get series of warnings like QOpenGLWidget cannot be used as a native child widget. Consider setting Qt::AA_DontCreateNativeWidgetAncestors and Siblings.. Furthermore, the documentation says "QGLWidget on the other hand uses a native window and surface. (...) QOpenGLWidget avoids this by not creating a separate native window.". Can QOpenGLWidget be integrated with third party OpenGL software at all, or is it unsupported now?
You need to create a QWindow, initialize it and integrate into application with QWidget::createWindowContainer
class MyNativeWindow : QWindow
{
MyNativeWindow() : QWindow
{
setSurfaceType(QWindow::OpenGLSurface);
}
};
MyNativeWindow *nativeW = new MyNativeWindow();
QWidget *w = QWidget::createWindowContainer( nativeW );
// Use w as a simple QWidget
In some cases you don't need to use winId to get HWND. It is enough to know OpenGL context id. For custom gl context manipulation you may use QOpenGLContext class.
Be careful, because if your third party libraries will create native windows (in OS X) by themselves, you will have a lot of bugs with Qt. We are tied to fix bugs in our project. (Undockable docks, keyboard focus lost, impossibility of opening menus, errors with fullscreen etc.)
You may look at this code sample. And a custom context code sample.

Auto resizing qt application. (main window)

I've recently started development in qt and so far it's going good. Now my question is : can I auto re-size qt application as per my screen resolution ? Say, I 've a main window designed for 1366 x 768. And it works for one system. While porting it to another system which supports 1280 x 800 or 800 x 600, is there an easy way to do it ? without changing UI design in creator ?
I appreciate any help regarding this.
Thanks in advance.
Try do this (for example put it in the mainWindow's constructor)
this->showMaximized();
Anyways you can simply get resolution of current screen with this code:
qDebug() << QApplication::desktop()->size();
And QWidget have resize() method. QMainWindow inherits QWidget, so you can use resize() in your mainWindow.
Qt (and many other UI toolkit) solve auto resize problem with a layout manager, it depend on how do you design your UI to choose a layout or mix them. See http://qt-project.org/doc/qt-4.8/layout.html

Qt FramelessWindowHint and WA_TranslucentBackground Font Rendering

I am writing an application with a custom window shell. The shell has rounded corners and transparency. Here is the sample code of how I am doing this:
MyWindow::MyWindow (void) : QMainWindow (NULL, Qt::FramelessWindowHint)
{
setAttribute (Qt::WA_TranslucentBackground);
setAttribute (Qt::WA_NoSystemBackground );
}
The problem is whenever I use WA_TranslucentBackground with FramelessWindowHint, the font rendering becomes awful, see image below. I have a custom application style set through a global css. I tried using other fonts such as Segoe UI however that font also becomes changed.
Any ideas on why this is happening and what I can do to fix this problem. I am using C++ with Qt 5.0.2
It looks like I may have found a solution. First of all, you can use QWidget::setMask in order to get rounded corners if you prefer to not use Qt::WA_TranslucentBackground. Here is the sample code I came up with:
void MyWindow::setVisible (bool visible)
{
// Call the default event
QMainWindow::setVisible (visible);
// Set a rounded mask (size() needs to be correct)
QBitmap t (size());
t.fill (Qt::color0);
QPainter p (&t);
p.setBrush (Qt::color1);
p.drawRoundedRect (rect(), 5, 5);
setMask (t);
}
For transparency you have to make the font prefer antialiasing. You can put this at the start of the application.
QFont font = QApplication::font();
font.setStyleStrategy (QFont::PreferAntialias);
QApplication::setFont (font);
Not perfect but it fixed the problem I was having.

How to display QWidget above data stream from device handled by external library

I'm creating application to analyze data from a device and displaying it on the screen. SDK to handling this device have function to display current frame of data in specific Window by setting window handler (HWND).
In my Qt Gui Application i'm trying display my own widget over video stream, which a DLL showing in my QGLWidget (it's set by winId function and HWND). MainWidget is a parent of QGLWidget where the data stream is displayed, and QWidget (or some graphic marker, for example Circle) should be displayed above data stream from QGLWidget.
Everything works almost perfect, but I'm getting blinking effect (twinkle effect?) - my circle widget is hidding and showing with frequency which human eye can get and i try to avoid it. The only option to eliminate that is create this circle as widget and set for its Qt::Popup flag, by it has big disadvantage - i don't have access to the rest of interface (I know, it's Popup flag fault). I've tried other options like:
set Qt::WindowStaysOnTopHint and few other flags,
create layout object which parent is QGLWidget, where i'm displaying data from device, and than set circle widget as item of layout, but here black background is shading displayed data (i've turned off even background, but i've realized that Qt can't know what is under my widget because it's handled by external library).
In documentation i found information that i can create my own directshow+COM object (or interface, am i right?) to handling video stream but i don't really know this technologies and i want avoid this option so much!
[Edit] I found that i can take current frame of data as IPictureDisp interface, but as I said earlier i don't really know COM technology. I've tried to find something about, how work with IPictureDisp but i don't have basic knowledge about COM technology. Does anybody has any good tutorial about it?
Try this widget hierarchy:
MainWindget
|-QGLWidget
|-MarkerWidet
MarkerWidet should be a small square widget.
Make sure that MarkerWidet is above QGLWidget by calling MarkerWidet::raise().
But call MarkerWidet::lower() before calling MarkerWidet::raise(). Qt has an error with QWidget::raise(), this error is eliminated by calling lower(); raise();.
After starting your application check actual widget hierarchy, use Spy++ to do it. Spy++ can be found in the Visual Studio installation, or downloaded here.
Pseudocode:
MainWindget* mainWidget = new MainWindget;
QGLWidget* glWidget = new QGLWidget(mainWidget);
device->setHwnd(glWidget->winId());
mainWidget->show();
...
MarkerWidet* marker = new MarkerWidet(mainWidget);
marker->resize(30, 30);
marker->move(10, 10);
marker->lower();
marker->raise();

resizing QGLWidget to fit with each sprite size I have

I'm creating 2D Map editor using opengl to draw simple 32x32 sprites but it seems that I cannot resize my QGLWidget to a large size (i.e size * sprite size -> 1024 * 32), using 1024 only seems to work fine (using glwidget->setMinimumSize(...)). I've been googling for a while now about this, the only interesting thing I found is subclassing QAbstractScrollArea and setting my QGLWidget as it's viewport (That's what QGraphicsView does), I also seen all Qt opengl examples but i couldn't find anything that could help (except Image Viewer example which is not exactly what I want), I also tried the following:
horizontalScrollBar()->setMaximum(width * 32);
verticalScrollBar()->setMaximum(height * 32);
with the widget resizable set to true/false on the scrollarea but still nothing.
Any ideas how would I do that? I can show more code if you ask me to.
Using Qt v4.7.3.
I have two ideas:
If it's possible, drop the idea of using a QGLWidget and place the sprites directly in a graphics scene (QGraphicsPixmapItem). Possibly not what you want, but the graphics scene is made to handle a lot of items, so most things you need (trigger mouse events on items for example) are already implemented.
Or just place the QGLWidget in a graphics scene using a QGraphicsWidget. This should automatically tell the scene its size, which then tells the view the size of the scene. The scroll bars appear automatically if the scene doesn't fit into the view.
Update:
As described in this link, you can use OpenGL in any graphics view:
view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);