Details Scroll area's setwidget function shows a toolbar - c++

I have a scrollarea and I'm setting a basic QWidget as its widget, However when I do this I get a toolbar on top of the widget I just set;
This is the slot I use to create the QWidget and set it to the scroll area, this happens during runtime and the qwidget is deleted and recreated repeatedly during runtime.
void SlotCreateDetailsWidget()
{
if (m_DetailsWidget == nullptr)
{
m_DetailsWidget = new DetailsWidget(); // QWidget
m_Ui->DetailsScrollArea->setWidget(m_DetailsWidget);
m_DetailsWidget->show();
}
}
What do I need to do to get rid of this toolbar?

From https://doc.qt.io/qt-5/qwidget.html :
A widget without a parent widget is always an independent window
(top-level widget).
What you see depends on the underlying windowing system but you can customize it up to a certain point with void QWidget::setWindowFlag(Qt::WindowType flag, bool on = true) for example. You can also look at https://doc.qt.io/qt-5/qtwidgets-widgets-windowflags-example.html.

Related

QWidget not displaying the QLabel

I have a QWidget which I want to use like a Dialog on top of another QWidget.
What I'm trying to do is a simple "Please wait while yadda yadda..." dialog with no buttons.
The code section is as follows:
void NewWindow::on_combobox_New_currentIndexChanged(int index) //slot function
{
QWidget* box = new QWidget();
box->setWindowModality(Qt::ApplicationModal);
box->setWindowTitle("Wait...");
QHBoxLayout* layout = new QHBoxLayout();
box->setLayout(layout);
QLabel* lbl = new QLabel();
lbl->setText("Loading...");
layout->addWidget(lbl);
box->show();
for (int var = 0; var < st.size(); ++var)
{
//Some heavy lifting here
}
box->close();
}
Normally I would expect this dialogue box to appear with the proper text and disappear after the loop ends. In fact it does that too but with one difference: The label does not display. The widget looks empty. Then disappears.
If I copy the code into a different area (for example to the MainWindow constructor) it displays properly with the message in it.
I sense that the loop blocks the draw operation but then the widget itself should be missing too. Why it is only the label eludes me.
Thanks for any insight.
Since you are creating and displaying this widget in a QObject slot, and then before returning from the slot, closing the widget, by the time Qt goes through the process of executing all your instructions, the last one is close, and so the widget disappears from view.
Underneath your slot, Qt is running in an event loop. Since control is never returned to the event loop, Qt never has an opportunity to render the graphics you've requested of it.
When you create widgets, add labels, etc, you are actually registering a bunch of commands with the event loop, which will only later be processed.
If you want Qt to render any changes you have made whilst in a slot, before returning to the event loop, you have to call processEvents.
Without doing so, you won't see those changes until control passes back to the Qt event loop.
So what is happening here, is that since you're also closing the widget at the end of your slot, Qt will create the widget, render its contents, and then immediately close it, and you won't see anything.
The reason for this is so that Qt can do calculations on what is visible, what isn't, be smart about what it renders etc, and only decide to draw what is necessary.
If it just rendered everything immediately, without waiting for control to return to it so it can process the "next batch of updates", it would likely be horribly inefficient.
So you need to put processEvents inside your callback slot.
void NewWindow::on_combobox_New_currentIndexChanged(int index) //slot function
{
QWidget* box = new QWidget();
box->setWindowModality(Qt::ApplicationModal);
box->setWindowTitle("Wait...");
QHBoxLayout* layout = new QHBoxLayout();
box->setLayout(layout);
QLabel* lbl = new QLabel();
lbl->setText("Loading...");
layout->addWidget(lbl);
box->show();
QCoreApplication::processEvents(); // cause the box to be displayed
for (int var = 0; var < st.size(); ++var)
{
//Some heavy lifting here
// if you do anything here to change the widget, such as
// updating a progress bar, you need to `processEvents` again
QCoreApplication::processEvents();
}
box->close();
}
As for why the widget window appears, but not the contents, this is likely because when creating the widget Qt sends a message to the Window Manager (in this case MS Windows), which will create the window on which Qt can render its contents.
So you see the result of Windows creating a new window for Qt, but nothing from Qt painting on that window itself.

Click on drop-down list of QComboBox

I currently have a QComboBox in a QGraphicsScene and I need it to detect clicks. To see if there is a widget in the clicked position, I use:
void BlockScene::mousePressEvent(QMouseEvent *event)
{
if (itemAt(event->pos()) != m_widgetItem)
{
// ...
}
}
This works well for different widgets except for combo boxes where it only takes into account the original widget and not the drop-down list that appears after a first click.
To know if it came from the scene or not, I tested also by redefining mousePressEvent of the class QComboBox and same problem: It is called only when clicking on the initial widget.
Is there a way to get the drop-down list? To detect a click on it? Ideas?
You can define a custom widget for the view of the combo, or for its completer.
For example, in a subclass of QComboBox, if you need a completer, try this code. MyListView is a subclass of QListView. On that, you can reimplement the mousePressEvent method
completer()->setCompletionMode(QCompleter::PopupCompletion);
MyListView *comboView = new MyListView();
completer()->setPopup(comboView);
if you don't need the completer, do the setView directly on the combobox.
MyListView *comboView = new MyListView();
setView(comboView);

Draggable QWidget

I have a MainWindow.cpp class with multiple images displayed that emit a clicked() signal. Once clicked on I want to open a widget that's a fixed size inside MainWindow and I want this widget to be able to be dragged around as long as it stays inside the MainWindow class.
I was looking at example code to try and write this widget class, in particular the Qt MainWindow Example. However, once one of the dockwindows are dragged around the display the Operating System specific titlebar (which lets you maximize, minimize, and close the window) gets displayed. I do not want this titlebar to be displayed.
How would I go about creating this class of draggable widgets?
Check setTitleBarWidget
Setting to a void widget will work:
It is not possible to remove a title bar from a dock widget.
However, a similar effect can be achieved by setting a default constructed QWidget
as the title bar widget.
Edit:
By request:
yourDockableWidget->setTitleBarWidget( new QWidget( yourDockableWidget ) );
In the example you are following, you could do it in constructor:
ColorSwatch::ColorSwatch(const QString &colorName, QWidget *parent, Qt::WindowFlags flags)
: QDockWidget(parent, flags)
{
/*...*/
setTitleBarWidget( new QWidget( this ) );
/*...*/
}
Now your widget wont have SO titlebar when undocked;

Change style on Hover state of parent QWidget in Qt

I have a composite control in Qt that is a QWidget with a QHBoxLayout containing 3 sub controls (QWidget > QHBoxLayout > 3 QLabels). On one of those controls, which is just a QLabel displaying an icon, I want it to change it's icon when hovering over the entire control. I can get it to work when actually hovering over that icon
QLabel#stateIcon {
image: url(:/icons/stateNormal);
}
QLabel#stateIcon:hover {
image: url(:/icons/stateHover);
}
However, I would like it to show the hover icon when the mouse is anywhere over the whole control.
I tried something like the following:
QLabel#stateIcon::parent:hover {
image: url(:/icons/stateHover);
}
and even
QLabel#stateIcon::parent::parent:hover {
image: url(:/icons/stateHover);
}
Hoping that it would activate on the hover-state of the parent but it does nothing.
Is there a way to do this purely in stylesheets?
If not, is there a way to propagate the parent hover state to it's children in code?
Maybe with an event handler dealing with the QEvent::HoverMove or QEvent::HoverEnter and QEvent::HoverLeave where you can set the attribute Qt::WA_Hover to your label.
I didn't try it but it should work as HoverEnter and HoverLeave causes update() function to be called.

Setting a QDialog to be an alien

In a standalone GUI application where I don't have a windowmanager nor a composite manager I want to display a QDialog to the user to ask for values.
The dialog is quite big, so I want to make it translucent so that the user can look through it to see what happens in the application while the dialog is shown.
The problem is that for translucency of X native windows, there needs to be a composite manager. Qt internal widgets can be painted translucent because they don't correspond to native X windows (aliens) and are completely only known to Qt.
Is there a way to make the background of a QDialog translucent without having a composite manager running? Perhaps making it a normal child widget/alien of the application's main window? Is there a better alternative to this?
I don't know of any way of turning a QDialog into a normal child widget. Looking at the Qt for X11 code, I can't figure out a way of not setting the Qt::WindowFlags passed to the QWidget (parent) constructor so that it would be a plain widget and not a window of its own (but I could be wrong, didn't spend a lot of time on that).
A simple alternative is to use a plain QWidget as your container, instead of a QDialog. Here's a sample "PopupWidget" that paints a half-transparent-red background.
#include <QtGui>
class PopupWidget: public QWidget
{
Q_OBJECT
public:
PopupWidget(QWidget *parent): QWidget(parent)
{
QVBoxLayout *vl = new QVBoxLayout;
QPushButton *pb = new QPushButton("on top!", this);
vl->addWidget(pb);
connect(pb, SIGNAL(clicked()), this, SLOT(hide()));
}
public slots:
void popup() {
setGeometry(0, 0, parentWidget()->width(), parentWidget()->height());
raise();
show();
}
protected:
void paintEvent(QPaintEvent *)
{
QPainter p(this);
QBrush b(QColor(255,0,0,128));
p.fillRect(0, 0, width(), height(), b);
}
};
To show it, call it's popup() slot which will raise it to the top of the widget stack, make it as large as its parent, and show it. This will mask all the widgets behind it (you can't interact with them with the mouse). It hides itself when you click on that button.
Caveats:
this doesn't prevent the user from using Tab to reach the widgets underneath. This could be fixed by toggling the enabled property on your "normal" widget container for example. (But don't disable the PopupWidget's parent: that would disable the popup widget itself.)
this doesn't allow for a blocking call like QDialog::exec
the widgets in that popup won't be transparent, you'd have to create custom transparent-background versions for all the widget types you need AFAIK.
But that's probably less of a hassel than integarting a compositing manager in your environment.