Attach a QLabel in front of QGLWidget - qt

I have a QGLWidget and I like to attach on top of it a QLabel for some measurement visualization (fps, number of object, etc).
I'd like to keep QGLWidget as clean as possible for further re-using and not use QGLWidget::renderText inside of it but use an external debug interface with those measurement.
For now I have:
QVBoxLayout *l = new QVBoxLayout;
this->gl = new MyGLWidget;
l->addWidget(gl);
QLabel *fps = new QLabel;
fps->setText(QString("FPS"));
fps->setStyleSheet("QLabel { background-color : red; color : blue; }");
fps->setParent(gl);
this->setLayout(l);
But nothing appears.. of course if I add the QLabel to the layout with QLayout::addWidget I see it.. but is not what I want..
Some ideas?

Without being assigned to a layout the widget doesn't know, where it should draw, if you don't tell it explicitly. You must call QWidget::setGeometry explicitly to position it.
However placing regular Qt widgets on top of a QGLWidget has some merits. The QGLWidget actually creates a subwindow parented by the top level window. Regular widgets however don't have their own, deidicated subwindows, which means, that from the point of view of the graphics system they're on the same Z stacking level than the top level window itself. And the QGLWidget's actual subwindow has a higher Z stacking level. Parenting a QLabel to the QGLWidget should place it at the right Z stacking level. But then OpenGL drawing operations are different than Qt drawing operations, so your drawing on the QGLWidget may mess up the QLabel.
Simply spoken, there's a reason why QGLWidget has a function "drawText".

Related

QT QVulkanWindow overlay widgets

I'm searching a way to draw any QT widget overlay on QVulkanWindow. I cannot find solution. Child/parent hierarchy and QT flags don't bring expected behaviour. Is it possible to draw QT widgets on the top of QVulkanWindow?
I've tried the following
1) attempt to create QWidget and Vulkan window from one parent QWidget
auto widget = new QWidget;
widget->resize(m_default_width, m_default_height);
widget->show();
m_label = new QLabel("text.", widget);
m_label->show();
m_vulkan_window = std::make_shared<WSQVulkanWindow>(this);
m_vulkan_window->setVulkanInstance(&m_qt_vk_instance);
m_vulkan_window->show();
auto wrapper = QWidget::createWindowContainer(m_vulkan_window.get(), widget);
wrapper->resize(m_default_width, m_default_height);
wrapper->show();
2) Added the following flags
m_label->setAttribute(Qt::WA_NoSystemBackground);
m_label->setAttribute(Qt::WA_TranslucentBackground);
m_label->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::CoverWindow);
Label is shown on top of vulkan window but it doesn't follow vulkan window position
3) Attempt to add QWidget::createWindowContainer of VulkanWindow and QLabel widget to one parent widget with QGridLayout or QVBoxLayout.
It has no effect
4) Create QVulkanWindow with parent newwidget->windowHandle() with following creation QLabel widget on newwidget parent
5) Create new QWindow with parent QVulkanWindow. After that create widget from QWindow and create child QLabel for mentioned widget.
winapi creates button on top of vulkan window. But it is impossible to create semi-transparent widgets
m_hwndButton = CreateWindowExW(
0L,
L"BUTTON", // Predefined class; Unicode assumed
L"VR", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
50, // Button width
50, // Button height
(HWND)m_vulkan_window->winId(), // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong((HWND)m_vulkan_window->winId(), -6), //instance
NULL); // Pointer not needed.
ShowWindow(m_hwndButton, SW_SHOW);
UpdateWindow(m_hwndButton);
Child/parent hierarchy and QT flags don't bring expected behaviour.
Once a surface is being managed by the GPU/Vulkan, you can't really expect to be able to draw native controls in it with something else.
Qt Widgets aren't really suited to rendering on a Vulkan surface. Widgets are typically native controls, so to display them on a Vulkan surface, you'd have to capture the widgets to an image, transfer that image to the GPU and then render the image.
If what you want to do is get UI inside Vulkan rendering, your best bets are either Imgui or QML. QML can be rendered to an OpenGL surface using QQuickRenderControl, and that GL surface can be shared with a Vulkan image using VK_KHR_external_memory. Imgui on the other hand is designed to be able to be rendered directly in a variety of GPU APIs, of which Vulkan is one. In both cases you will be responsible for capturing Qt events and passing them to the Imgui or QML layer.

Drawing inside a QFrame: coordinate system

I would like to draw inside a Qt QFrame, however the QFrame will have a border. As far as I understand, the paintEvent receives a QPainter which is associated to the whole frameRect, so I will have to offset my paint operations of the border. Is this correct? Is there a way of getting a QPainter already associated to the inner part of the widget, without the (variable in size) border?
you have to consider the contentsRect contentsRect()-> Returns the area inside the widget's margins.using the return value rect of contensRect() you can restrict to draw anything inside the rect.
One way to do this would be to embed a QWidget inside the QFrame, place it in a simple QVBoxLayout layout or QStackedLayout layout with no margins and paint the QWidget instead. You'll probably get better performance if you simply offset your painting, though.

Qt : event invisible widget?

For some reasons, I need to draw a widget onto one another.
The structure is the following (see the image) :
I have an original QTableWigetItem
On the QTableWigetItem, I create a QWidget at the foreground with the same geometry
This QWidget contains a QBoxLayout
This QBoxLayout contains a QPixmap and a QComboBox
I want to do the following things :
The QWidget is just a "container" for my QBoxLayout and I would like to set him completely "invisible" for the user. If the user click or move at the position of the widget, I want the event of the QTableWigetItem in the background to be trigerred. But the problem is that I want the QPixmap and the QComboBox to be at the foreground, visible and "normal". For me it's just a trick to be able to put children widgets in a QTableWidget of a HeaderView.
How to make the QWidget "completely invisible" (from the event/signals point of view) ?
Thank you very much.
Try QWidget::setWindowOpacity(0)

Layering UI elements in Qt Designer

I have a QLabel that I'm constantly setting it's pixmap (video playback). In my application the user needs to be able to draw (boxes) above the video. How can I layer one of the QPaintDevice classes (QWidget, QPixmap, QImage, etc.) directly above and with the same size as the QLabel for painting. This element will need to have a transparent background so shapes drawn on it will appear over the video.
Add the widget you want to draw shapes on as a child widget of the video label. Add a layout first so the child widget will match the size of the parent widget. The code would be something like this:
QHBoxLayout *layout = new QHBoxLayout(videoWidget);
QLabel *overlayWidget = new QLabel();
overlayWidget->setAlignment(Qt::AlignCenter);
overlayWidget->setText("Overlaid Text");
layout->addWidget(overlayWidget);
You should see the text overlaid on the video and it should remain centered over the video widget if it is resized. For your final code, you would use some widget subclass of your own that allowed you to intercept mouse actions and draw rectangles but that's the basic idea.

How does QWidget size when used as a window?

Several examples on trolltech use QWidget rather than a QMainWindow as the main window for simple Qt applications.
Now I need just a simple window with a single content widget (QGlWidget) that covers the entire client area.
However, when I show a QWidget window with a single content window it automatically resizes itself to be tiny.
If I create the QWidget parent window without a child It is a nice large default size.
I don't want to resort to using Layouts for a single child window :/
What I understand is that you use a QWidget to display your QGIWidget. Try calling the show method of your QGIWidget directly (if your QGIWidget class inherits QWidget), Qt will create the window decoration for you.
Otherwise if you really need your widget to be inside one another, and fit its size, you'll have to use a layout.
Either follow gregseth's advice or you can simply resize the widget yourself.
(though this way you'll loose nice auto-resizing which is provided by Qt when you use layouts)
In your case you can basically do something like:
QGlWidget* myWidget = new QGlWidget;
myWidget->resize(QApplication::desktopWidget()->availableGeometry().size());
// or maybe instead of resizing show it in fullscreen:
myWidget->showFullScreen();
(actually I don't remember if showFullScreen() will do resizing for you, maybe you'll need both resize+showFullScreen :))
Cheers :)
P.S. Using layout is actually an option. It's not expensive and it's flexible. All it gets: "layout = new QVBoxLayout(myWidget); layout->addWidget(myWidget);" and you're done :)
Not always.
I've found that a QMainWindow will not work as the parent widget when using the QVBoxLayout and QHBoxLayout to arrange child widgets.
If you create a QWidget and use that in place of the QMainWindow then the layouts will work correctly.
QWidget* centralWidget = new QWidget( MainWindow );
MainWindow->setCentralWidget( centralWidget );
If you use QtCreator and look at the code it creates you can see it creating a 'hidden' widget if you try to use the layouts directly at the top level.
It's not obvious, intuitive, or documented anywhere that I've found.

Resources