Tell where the showEvent is from - qt

I have a QTabWidget, and I defined showEvent for one of the child widget.
Now how can I know where the showEvent is from?
It could be:
Switched from other tabs
The current index of tabwidget was not changed, the whole window just become visible
Is that possible?

QShowEvent is very generic, so there's no direct way to get information about what triggered it. Depending on your needs either save current value of QTabWidget::currentIndex between show events or move your logic to QTabWidget::currentChanged slot.

Related

Difference between hide, close and show in qt

What is the difference between hide,close and show of pushbutton or any widget in terms of memory?
Which is better if I don't want to use widget again?
First as said #Hayt, read the documentation.
For the actual answer:
hide() is the same as setVisible(false).
show() is the same as setVisible(true).
close() attempts to close the widget by triggering a QCloseEvent, if the event is accepted the result is:
The same as calling hide() if Qt::WA_DeleteOnClose attribute is not set on the widget which is the default.
The same as calling deleteLater() if Qt::WA_DeleteOnClose is set.
In term of memory, any of the 3 will not change anything (except for close() if you have set Qt::WA_DeleteOnClose). If you do not want to use the widget ever, the best is to delete it:
delete pointerToMyWidget;
or
pointerToMyWidget->deleteLater();
The second form is generally safer as the 1st one can be dangerous depending on where your write it. (e.g you delete it in a slot called by a signal emitted by the widget you delete).
According to Qt, you can read this :
CLOSE :
Closes this widget. Returns true if the widget was closed; otherwise
returns false.
First it sends the widget a QCloseEvent. The widget is hidden if it
accepts the close event. If it ignores the event, nothing happens. The
default implementation of QWidget::closeEvent() accepts the close
event.
If the widget has the Qt::WA_DeleteOnClose flag, the widget is also
deleted. A close events is delivered to the widget no matter if the
widget is visible or not.
The QApplication::lastWindowClosed() signal is emitted when the last
visible primary window (i.e. window with no parent) with the
Qt::WA_QuitOnClose attribute set is closed. By default this attribute
is set for all widgets except transient windows such as splash
screens, tool windows, and popup menus.
.
HIDE : Hides the widget. This function is equivalent to
setVisible(false).
Note: If you are working with QDialog or its subclasses and you invoke
the show() function after this function, the dialog will be displayed
in its original position.
.
SHOW : Shows the widget and its child widgets. This function is
equivalent to setVisible(true).
If you don't need to use your widget, call close(). You can manage the event to destroy your widget.
hide() only hides. It's only graphical, you can't see your widget but you don't destroy it.
But I think that the name fo the function are enough explicit to understand!

How to enable both internal reordering and external dropping in a Qt widget?

I have created a widget which inherits QListWidget.
My goal is for it to accept files dropped into it from an external file manager, and for the user to be able to reorder the elements in the widget. I can achieve both, but not at the same time.
If I just set
myWidget->setDragDropMode(QListView::InternalMove);
myWidget->setDragEnabled(true);
I can reorder the items within the widget, but I can't drop external items into it.
If I reimplement the dragMoveEvent, dragEnterEvent and dropEvent events, all of them just having acceptProposedAction(); and some debug messages inside them, I can drop external files into my widget, but I can no longer rearrange the items.
Is there a way to have the above two at the same time, or do I have to manage the items myself in the reimplemented functions? If so, how can I know if a dropped item is internal or external, and how can I know from which position it was taken and into which position in the list it was dropped into?
If I parse the mimeData which I got from the event, I can see whether it as a file or a text, and I get "qabstractitemmodeldatalist" if it was an internal item, but it still doesn't give me its position.
I can check event->pos() to know in pixels where the drop has been made, and event->source() to learn about what was dropped there, but is this really best practice, to start calculating pixel values and adding objects "manually"?
The solution was very simple: I just had to call the functions of the parent class at the end of each function I've overridden.
void myWidget::dropEvent(QDropEvent *event)
{
do_stuff_with_received_data(event);
QListWidget::dropEvent(event);
}

QAbstractItemDelegate painting while dragging problem

I'm overloading the paint() function in QAbstractItemDelegate (my own Item delegate class).
When dragging, it paints the contents of the entire cell, which I don't want. I'm assuming that the paint() function is called with something specific while dragging, but I don't seem to find it.
The closest I've been able to find is a QState variable in the owning view class (access function QTableView::state() is protected.) By creating a function on my QTableView-derived class called 'isDragging()' which calls that function and returns whether dragging or no, I can determine within my delegate class whether I'm dragging or not, and can modify the paint() function.
This almost works.
The problem is that it shows the modified paint image in the original cell, which I don't want - I want to leave the image in the original cell untouched.
Have to scour the examples, I guess, and see if there's something that does this...
I have crawled through the Qt source and I can see where it sets the drag pixmap by calling the QItemDelegate::paint() function, but the only thing it changes is it forces QStyle::State_Selected in the item option style. That's not enough, since the item is selected, already.
Any way to know how to draw a cell's contents explicitly when dragging?
Ok, the ultimate answer on this was to, yes, set the flag on 'startDrag', but rather than leaving it around and unsetting it on mouse release button event, simply call the base method and then unset.
The reason is that the image for the cursor is only requested (and painted) once - not continuously during the drag, as I had first thought. Leaving the flag set meant the cursor image would get drawn at inappropriate times.
So, the implementation looks like:
MyClass::dragStart(Qt::DropActions supportedActions)
{
__dragStart = true;
TableView::dragStart(supportedActions);
// request for drag cursor image happens here
__dragStart = false;
}
Why don't you do that yourself? Set a flag when dragging starts and remember the active ModelIndex, do some special painting when the flag is set, and clear the flag when dragging is finished. You can do this by overriding QAbstractItemView::startDrag.

How to force calling of QWidget::paintEvent() when its hovered by other window?

I have a problem:
I'm creating a widget which displays current date's day number. It's like a button, but it's not derived from QPushButton class. Just from QWidget. So I've reimplemented enterEvent(), leaveEvent(), mousePressEvent(), mouseReleaseEvent(). I do call update() inside these methods and widget has realistic button behavior (paintEvent() is reimplemented also).
But when I change system date and hover that widget with other window, my widget doesn't get paintEvent() and the old date is displayed. Only when I place mouse over it, widget repaints it's contents.
I guess there is a feature (like buffering) which paints old contents on hovering with other window to avoid unnecessary recalculations. But I need to disable it. Tried to set many attributes (the Qt::WidgetAttribute enum). But it doesn't work.
I think you should find a way to detect that the system time has changed and call update() when that happens. Any other method (like detecting the "hovering" of a window or waiting for a mouse event) will cause the update to occur too late.

How to remove QWidgets from QSplitter

In my app have a window splitted by a QSplitter, and I need to remove an widget.
How can I do that? I can't find useful methods
It's not clear to me if you want to preserve the widget and put it somewhere else, or if you want to destroy the widget.
Destroying the widget: If you can
get a pointer to the widget, you can
simply delete it. The splitter will
safely be notified that its child is
being deleted and will remove it
from itself.
Preserving the widget: If you grab
the pointer to the widget, you can
simply set its parent to some other
widget and add it to another
widget's layout and it will show up
there. This is safe because the
QSplitter will be notified that one
of its children is being reparented.
If you want to set the parent to NULL (cjhuitt's answer) be aware that you are now responsible for cleaning up that memory because the widget no longer has a parent.
Many things in Qt cannot be "traditionally" removed. Instead call hide() on it and destruct it. From QSplitter documentation:
When you hide() a child its space will
be distributed among the other
children. It will be reinstated when
you show() it again.
I like Tuminoid's answer. But if you absolutely need it removed, try getting the widget you want to remove, and calling setParent( NULL ) on that widget. That's my best guess.
If you hold a pointer to the widget, then just delete it, or use deleteLater() if you want to be on the safe side.
If you do not have the widget pointer, use QSplitter::widget(int index) function. Then, you can use invoke its deleteLater() slot.
If you do not have the widget index, but you still know the widget objectName(), then QObject::findChild() is your only way to get the widget pointer.
I ran into the same problem. In Qt 4.8 to temporally hide one of the widget of a QSplitter I simply hide it. However it is not enough, as the splitter handle is still available to move. But the handle can be accessed and hidden as well:
frameA->setVisible(conditionA);
frameB->setVisible(conditionB);
if ( !(conditionA && conditionB) ) // if only 1 frame is visible
{
splitter->handle(0)->setVisible(false);
}
Another easy way to prevent the child widget from getting deleted is to use QSplitter.takeWidget(child). This is also the recommended way of removing the widget from a splitter. (Qt Documentation)

Resources