QTreeView activated signal
I use Qt 4.8 on Windows 7 and find QTreeView (or rather QAbstractItemView) activated ( ) signal behavior very strange,
My assumption is that rectangle has to be shown around an active item
(the same as selection in a single selection mode).
But instead single click on the item does change the visual presentation of the active item - bounded rectangle is moved,
but activated ( ) signal is not emitted.
Documentation does state that such signal is emitted either on a single click or double click depending on platform, but I do not see any logic in changing active item visually and not emitting the signal.
All this achieves is confusing the user who can't track anymore when current item is changed. Google it and you will find multiple questions and no answer.
Logical behavior is either not change an active item visually and then do not emit signal or change and emit.
In fact it was not that difficult to change it with style sheet:
" show-decoration-selected: 1;"
But default behavior seems at least unexpected.
I think the confusion comes from the terminology so lets make clear what is what.
We need to distinguish what is meant when item is selected, current or activated, as these are three different concepts.
A selected item is tracked by selectionModel. A selected item usually has visual representation. For most default styles some sort of colored background or different font. There can be multiple selected items at any given time.
A current item, tracked by currentIndex, is the item that is marked for user interaction. It can have a visual representation but doesn't have to. For example the default behavior on Windows is that it doesn't have distinct representation for mouse actions, but gains a dashed line around an item when interacted with by keyboard. There is always at most one current item and it doesn't necessarily have to be selected (e.g. by navigating with keyboard).
An activation is an event, not a state like the ones above. An item is activated by certain user actions and doesn't "stay" activated. As such, activation doesn't have a permanent visual representation. It can have a momentary one, e.g. showing a click place when visual aids are enabled in the system. Activation is an action from a user that triggers some item interaction on the current item. For example activating an item in a tree view will open/close its children tree. Activating an item that doesn't have children does nothing by default.
Now to what happens when you click an item (I'll talk about default behavior on Windows, customization is of course possible).
- When you click (once) an item that is neither selected nor current it becomes selected and current. Its visual representation will reflect the selection and (if previously interacted with keyboard) current state. The item is not activated.
- When you click (once) an item that is selected but not current it becomes current. If keyboard was used previously it will gain additional visual representation in the form of dashed rectangle around the item. The item is not activated.
- When you double-click an item that is neither current nor selected it becomes current, selected and then is activated. It gains visual representation of selected and current states. The item is activated and an action associated with activation is performed (e.g. tree expand/collapse).
4., 5. and 6. are when you double-click on an item that is either current, selected or both, in which case the item becomes current(if it wasn't already), selected(if it wasn't already) and then is activated.
Thanks Chris for perfect explanation.
Looking back at my projects where it was satisfactory to use QTreeWidget I've noticed I used currentItemChanged signal for such purpose.
I think QTreeView or even QAbstractItemView requires similar signal like:
void currentIndexChanged ( const QModelIndex & current, const QModelIndex & previous );
I can subclass and override protected slot QAbstractItemView::currentChanged to emit such signal,
Do you have any idea why such signal was skipped there?
Were there performance issues for general case?
Sorry, I don't know the reasoning for this.
A wild guess would be that it's to allow customization of when such signal is emitted.
For example if you wanted to allow only every other item to become current (for whatever abstract reason) you could subclass QTreeView, override
currentChangedand either call
setCurrentIndexon a next item or emit the signal, depending on the current row index.
currentChangedis protected and you control the signal emission this would be nicely black-boxed to the user of such class.
QTreeWidget is a convenience class that serves the simplest needs so it exposes this signal in the simplest form.
Sort-of related question: Why is there an " entered" signal (like a widget enterEvent) but no "leaved" or "left" (like a widget leaveEvent).
How do I do something using "entered" e.g. highlight something else when the item is highlighted and then undo it when the item is no longer hovered?
Is there an equivalent to a "I have left this item" signal?
@GeorgePTVS For concrete answers to "why" questions you should probably ask the people who designed it on the mailing list. I can only offer my guesses. I think it's to, again, allow customization of the behavior. A rectangle of non-hovered item is known so the
entered()signal can be emitted safely. In response to that signal the item can be manipulated in some way e.g. some visual overlay could be shown (like a highlight effect, a menu or something else like that) and then it would be impossible for generic implementation to decide when such custom area is left by the cursor and should it be considered item's area at all. Because of that it is left to the implementer of the view customization to emit such signal when appropriate for his specific implementation.
As for answering the "how" question - once you enter the item you get the
entered()signal. From there you can take its index from the parameter and use it to get a rectangle of the item using
visualRect(). With that you can check in
mouseMoveEventif the mouse has left the area and emit a custom signal. To be complete you should probably also handle scrolling of the view to take care of the case where item scrolls out from under the motionless cursor.
Thanks for your thoughts. Yes, I do not really want to know "why". Just: Is it there? The answer seems to be "No". I had thought about manually tracking the mouse...sounds painful and unrobust.
I'm trying to have the :hover state of two QTreeViews stay in sync. I have it working for QToolButtons using enterEvent and leaveEvent bu there are no such events for QTreeView items (that I know of). The "entered" signal sounded great and works, but is useless without an equivalent "exited" (I called it "leaved" or "left" previously.)
I saw a somewhat similar old post of yours here.