QT QVulkanWindow overlay widgets - qt

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.

Related

QT layout manager does not recover space when hiding widget until window is moved

I am using Qlabels to plot some graphs and images (via setpixmap).
My basic layout is:
QVBoxlayout main layout via qdialog's setlayout.
QHboxlayout (array of QLabels)
Qlabel expandedPlot (optional expanded plot of one of the above QLabels)
QLabel mainImage Main image display
Within the QDialogs re-implemented keypress event handler, I hide()/show() the expanded plot. When I hide() the expandedPlot, the layoutmanager recovers about 1/2 of the vertical usage. Then when I drag the window, the layout manager recovers the remainder of the vertical space (as if there was no item present).
How can I force the behavior of moving the window? I want the layout manager to completely recover the vertical space.
I am using Qt 5.6 on windows, but want cross-platform solutions.
Thank you, mike
Because laying out the widget is quite expensive, Qt doesn't always do it. If you change the size of enclosed widgets you are likely to need to call updateGeometry on them to trigger the enclosed layout manager to re-layout. But if you hide the widget, updateGeometry does nothing. In that case you need to call adjustSize on the parent widget, which will then trigger the re-layout.

Qt ScrollArea on widget messes up size and position of widget [Qt 5.1]

I'm new with Qt and I want to implement a scrollable widget which can grow dynamically, e.g. by adding buttons into it when another button is pressed. I try to implement it using the following layout and code:
scrollArea = new QScrollArea(ui->outerWidget);
scrollArea->setWidget(ui->innerWidget);
layout = new QVBoxLayout(ui->outerWidget);
ui->innerWidget->setLayout(layout);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// code for PushButton to add buttons in innerWidget
void MainWindow::on_pushButton_clicked()
{
QPushButton *button = new QPushButton("button"+QString::number( nameCounter ));
nameCounter ++;
ui->innerWidget->layout()->addWidget(button);
}
This implementation has two problems when I run the program, first the innerWidget appears out of place (I define its position in Qt Creator's Design mode) and second after many widgets are added in the layout the scroll bar is doesn't grow, but instead the widgets are become smaller to fit into the layout:
In another thread it was suggested to set widgetResizable to true:
scrollArea->setWidgetResizable(true);
The scroll bar seems to work now but the new problem is that the innerWidget becomes very small so it is barely visible:
So, how can I achieve a scrollable widget that will respect the size and position of the design?
have no environment to verify but good luck.
to place scrollArea the target position,
Manually call SetGeometry, or
Place a QScrollArea in ui form, (suggested if it's static), or
Place a widget in your target position, and set QScrollArea's parent to it, and add QScrollArea to its layout, and Set QScrollArea to be expanding.
manually create a QWidget innerWidget and assign it to scrollArea via QScrollArea::setWidget(*QWidget), try different size policy to innerWidget, such as "Preferred".
Also be aware of Qt's reference mentioned : void QScrollArea::setWidget ( QWidget * widget )
Sets the scroll area's widget.
....
Note that You must add the layout of widget before you call this function; if you add it later, the widget will not be visible - regardless of when you show() the scroll area. In this case, you can also not show() the widget later.
Above list solutions, below are reasons to the problems you mentioned:
scrollArea->setWidget(ui->innerWidget); Setting a widget to ScrollArea will change the parenting and layouting of ui->innerWidget, so the geometry values written in ui form (in Qt Creater) will no longer take effect, this is the reason of innerWidget out of place. ui->innerWidget is no longer a child of outerWidget, it's geometry will follow its new parent (but not scrollArea, there's some tricky layouting inside QScrollArea". To be clear, innerWidget is not helpful to locate scrollArea in such scenario.
In your first clip of code, widget 'scrollArea' is created with parent outerWidget, again no size policy or layout or geometry is specified, so scrollArea will by default be placed at the left top corner of the parent "outerWidget". To place scrollArea to your target geometry, you can " set geometry manually " or " assign innerWidget as scrollArea's parent and expand scrollArea". Obviously the latter method cannot assign ui->innerWiget to scrollArea->setWidget().
scrollArea->setWidgetResizable(true); makes the scrollArea "shrink" at left top corner of outerWidget. This is because, QScrollArea does not increase along with it's contents, it can scroll to display all of it contents so the required size of QScrollArea can be as small as possible. Once the 'Resizable' property is set to "true", QScrollArea decides to shrink to its minimum necessary size, thus the size to display its scroll bar and scroll buttons....

How to prevent QTableWidget from occupying the whole window in a QHBoxLayout?

In my Qt program, I programmatically generate a modal QDialog. I want to show two widgets in this dialog window: A custom widget showing a camera output and a QTableWidget, showing the pixel coordinates of the corners found in the camera image. I generate a QHBoxLayout and add my custom widget and the QTableWidget into it. Then I set this QHBoxLayout as the Layout of the QDialog window. What I want to achieve is to share the available space in the QDialog's window area equally between my custom QWidget and the QTableWidget, horizontally, by using a QHBoxLayout. But I always end up with QTableWidget occupying the whole QDialog area, by overlapping my custom widget. How can I instruct these two widgets to exactly share the QDialog area?? Note that I first add my custom widget and then the QTableWidget into the QHBoxLayout.
Make sure on your custom widget you've specified a minimumSizeHint and a sizeHint, this instructs the QLayout manager that the widget requires a specific space. To have them split equally you'll be best off detecting the size of the QDialog and then specifying the width for both by removing the boundary sizes (spacing between widgets + space to QDialog edge) and dividing it up.

Attach a QLabel in front of QGLWidget

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".

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.

Resources