How can I disable a Qt widget without changing its appearence - qt

I have a Qt widget which has a layout and there are more widgets inside it. When I disable the widget the whole widget becomes little faded and no modifications are possible anymore. I want the features that comes with disabling a widget but I do not want it's appearance to change. Please let me know how this can be done.
Few ideas that comes to my mind:
Rather disabling widget, capture all the events on the widget and do nothing
Update style sheet for disabled state (not sure if possible)

1. Capture events
Use QObject::installEventFilter() and QObject::eventfilter().
Keep in mind the way Qt dispatch GUI events, in particular children get events first. So you need to install the event filter recursively on all widgets and watch for QEvent::ChildAdded.
2. Using stylesheets
This is a not a good solution. Stylesheets tend to break QStyle mechanisms which may lead to side effects.
3. Use a QPixmap
Hide all the child widgets, render them to a QPixmap and draw the pixmap in the paintEvent.

Related

How to gray a group of widgets when they are disabled?

There is a QGroupBox full of widgets, and all of them need to be disabled and grayed out.
setDisabled(true) does disable them functionally, but they don't turn gray.
What is the easiest and most proper way to turn them gray?
This should be a standard operation: text turns gray so that users can easily see that they are disabled.
QWidget::setDisabled() is yet (another) slot for the QWidget enabled property.
From Qt doc.:
This property holds whether the widget is enabled
In general an enabled widget handles keyboard and mouse events; a disabled widget does not. An exception is made with QAbstractButton.
Some widgets display themselves differently when they are disabled. For example a button might draw its label grayed out.
(Emphasizing by me.)
How widgets are displayed depends on their respective rendering as well as the (default) QStyle which is used in the application.
Concerning custom widgets (classes derived from any "built-in" Qt widget) where paintEvent() is overloaded, the custom widget is itself responsible to render accordingly to different states.

How to draw something in a tooltip?

I am trying to develop a functionality using Qt which I don't know whether it is possible to implement. Here is the requirement:
When the user hovers over a node (an object derived from QGraphicsItem), a window will be shown near the node, in the window there might be some histograms or buttons that can be clicked to show further information. When the mouse leaves the window, it will automatically close.
I tried to use a tooltip, because it can pop-up near the node and close when the mouse leaves it, but it can only show text. So, it still cannot work that way. I am wondering if there is another way to do this? I did lots of google search, but there is still no answer.
Thanks so much for helping me with this.
If you're ok with using a 3rd party library, Qxt provides a class that provides a tooltip that is QWidget based, which will let you use an arbitrary widget as the tooltip rather than just text.
See: Qxt::ToolTip
you don't have to use tooltip for your app
you can use or call widget or dialog, on hover mouse event
Please refer Qt Example EmbeddedDialog Example, It is advanced, But you can understand how hover Enter/Leaving events are working. I personally prefer don not create instance of Popupdialog for each item, create it if only nesessary. Otherwise create one dialog and pass its reference to all the items through the constructor initialization.
1. These are the API you are intrested on, reimplemet this.
QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) and void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
2. When You create Dialog, You can pass Qt::WindowFlags as Qt::ToolTip.

Best way to display dynamic element on a QListView (with Model/View)?

We can implement our own delegate to display rich text or images, but ListView can print static item only. You can't put "real" items into it, you can just paint them.
So, there isn't a way to show clickable hyperlink, ReTweet buttons, or load asynchronous images. Just think about a timeline-listview for Facebook or Twitter. That's what I'm working on.
Now, my solution is writing my listview in QML. Other widget are still native Qt widget. (I don't like a non-native pure QML user interface.)
QML is really flexible when doing that kind of work. Then export my model, finally put a viewer into my QMainWindow. But coding in two programming languages and trying to communicate with other native widget is really difficult.
So, what's the best way to display dynamic element?
The MVC framework is not very good for this kind of work.
To do it properly, you would need to provide a delegate for whatever dynamic types you need to display, and then provide an external mechanism that forces the model to emit dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) whenever these types need redrawing. It gets worse with interactive content because you would need to force an update on mouse overs in order to trigger the delegate painting.
For stuff like this you are better off using QGraphicsScene/View. Rather than rely on a model, each item can take of itself and you still get only essential repaints (via it's BSP structure), plus you have the option of hardware acceleration.

How to update a QLayout and get the new dimensions before returning?

This is driving me nuts. I have a custom menu class that, when set visible, shows a list of items located in a particular folder. When a hardware button is pressed, my application gets the latest list of items, populates the menu with them, and returns.
The menu displaying these items uses a QListWidget filled with custom widgets. Each of the widgets contains one or more QLabels in a horizontal layout, and is created at the time the menu is shown. In order to adjust the text displayed based on the menu width available, I need to get the size of the QLabel AFTER it has been resized according to the layout, but before the menu becomes visible to the user. The problem is, my layout does not get updated until all of the functions constructing my list return.
I have tried QApplication::ProcessEvents() and the layout update functions, but none of them have updated the values of my QLabels before returning. I can set a QTimer when the button is initially pressed, and have it show the menu, update the items, and stop itself, but that seems like a terrible solution.
Any help would really be appreciated! I've spent most of a day on this.
Marlon
I had this exact problem and could not find an answer anywhere on the Internet. Calling Layout.update(), Layout.activate(), or widget.adjustSize() (all suggested in various places) all did not work.
I had a widget with a vertical layout that I wanted to add a QLabel to and then immediately use the size of the QLabel.
The only thing that worked reliably was
layout->addWidget(myLabel);
myLabel->show();
size = myLabel->size();
It would seem that layouts will just not recalculate until you either return from a function and allow the Qt event loop to progress or manually call show() yourself.
How to update a QLayout and get the new dimensions before returning?
Don't. You're not meant to do that. It'll drive you "nuts" because you're doing it backwards. Layout updates are handled asynchronously from the event loop. Instead of getting layout dimensions right away, set yourself up to be part of the system. Some options are:
Implement a custom widget that will interact properly with the layout, growing to fill the available width of the layout. Perhaps all you need is a size policy and a way to elide text?
Make a custom layout that takes the special properties of your use case into account.
You want to call QWidget::adjustSize() on your parent widget. This will force the layout recalculations.
Have you tried using layout()->update(); ?
I've tried many but nothing works for me on Qt 5.15.
Only invented little patch - create timer and get size after 20 msec:
QTimer::singleShot(20, this, [this]
{
const auto height = myLayout->contentsRect().height();
// ...
});

Reducing flicker with QBoxLayout

Whenever a displayed QBoxLayout is populated, there's some flicker on the screen as widgets get added to the layout. How do I stop this flicker?
setUpdatesEnabled did not do the trick.
show() the widget only after you've finished populating it/laying it out.
Or don't attach your layout to it's widget before you're done adding things to it. (i.e. only call setLayout(your_layout) when you've finished adding things to your_layout).
Alternatively, look into the updatesEnabled QWidget property. You can use that to temporarily disable the widget's updates to prevent flicker. (This is most useful on the more complex widgets like QTableWidget and similar when you are making "massive" changes to the underlying data.)
Quote from the doc above:
setUpdatesEnabled() is normally used to disable updates for a short period of time, for instance to avoid screen flicker during large changes. In Qt, widgets normally do not generate screen flicker, but on X11 the server might erase regions on the screen when widgets get hidden before they can be replaced by other widgets. Disabling updates solves this.

Resources