0

I'm programmatically changing the selected item with setCurrentIndex() of my Tree- and TableViews.

If the current item has changed, a multitude of signals are emitted (currentChanged(), currentColumnChanged, etc).

I'm listening to some of these signals in order to be informed when the user changes the selection.

Is there a way/a signal to distinguish between user-selected and programmatically selected events?

I tried using the activated()-signal on the views, but this seems to not behave the same way on different platforms (sometimes activated is triggered only if double-clicked).

Patrick B.
  • 11,773
  • 8
  • 58
  • 101

3 Answers3

1

Maybe, you could just block all signals while making your change?
QSignalBlocker or QObject::blockSignals could help:

{
    const QSignalBlocker blocker(myWidget);
    myWidget->setCurrentIndex(someIndex);
}
MasterAler
  • 1,614
  • 3
  • 23
  • 35
  • 1
    This works fine, but you have to block signals on the view's `selectionModel()`, not on the view itself. – Patrick B. May 04 '22 at 09:00
  • Actually, after some testing, this breaks the GUI functionality, blocking Signal in the view or in the selectModel is not the best way. – Patrick B. May 04 '22 at 21:49
  • @PatrickB., that's actually strange, are you unblocking the signal right after the change? Maybe some update / invalidate / `emit layoutChanged()` could help? What confuses me is that smth else in GUI breaks because of blocking selection or index. You could use `disconnect + connect` but that would be even more of a trick, imho – MasterAler May 04 '22 at 21:54
  • This symptoms are that the GUI-representation of, e.g. the tableview gets messed up when quickly selecting columns/rows. Because signals are getting scheduled while the previous signals are not yet finished. During that blockSignals() is still true. Or at least that is my explanation. – Patrick B. May 04 '22 at 21:59
1

What I finally did, and it works in my case because I have a single-thread application, I created a custom variable programmatic-select, which I set to true before calling setCurrentIndex(). In the changeSelection()-slot I check this variable and do nothing if it is true.

Very important for this to work is to connect the slot to the signal with the connection-type DirectConnection. In this case the slot is executed synchronously when the signal is emitted and I'm sure the value of my variable is safe.

Patrick B.
  • 11,773
  • 8
  • 58
  • 101
0

In your slot, you can use QObject::sender() to return the QObject to you. From there, there are a handful of ways you should be able to distinguish the source.

mzimmers
  • 857
  • 7
  • 17
  • In both cases (user selection, programmatic selection), the sender is the view or the selectionModel. – Patrick B. May 04 '22 at 09:00
  • The programmatic events you speak of - are they things like timers, etc? If so, you could use QObject::isWidgetType() on the object returned by QObject::sender(). You might also look at QObject::senderSignalIndex() -- I've never used that one, but it seems to be for cases like yours. – mzimmers May 04 '22 at 13:32
  • Working with the sender is tedious, unfortunately and leads to nothing. What I'm trying to to do is to workaround a Qt feature, and this is not intended. Thanks for your insights, though. I have a solution which works. – Patrick B. May 04 '22 at 21:51