1

I have multiple tabs that a user can switch between. I need a widget on a given tab to run an exit function when that tab is no longer selected. For example, if the user currently has tab_1 selected, when they switch to tab_2, tab_1 should run some exit function. Is there an event that gets called when a tab looses focus?

I can run functions when a tab is selected using QTabWidget.currentChanged. I could use a variable to keep track of the previously selected tab and select the required exit function using this but that feels clunky.

3
  • 1
    It's not clunky at all, at least in principle. In fact, that's exactly what it needs to be done: keep a persistent reference (usually, an instance attribute) to the current tab, so that when the active tab changes, you can know the previous one, do whatever you need with it, and then update that reference to the new tab index. Commented Jun 15 at 0:17
  • I was toying around with a function in the QTabWidget already, using a variable to keep track adds 2 lines of code. I think it's clunky because each tab-widget needs an exit function and the QTabWidget has to have a function to select which to run. I was hoping to have everything a bit cleaner and not have to add anything to the QTabWidget when a new class of tab widget was added. But, easy enough I guess. Commented Jun 15 at 4:33
  • 1
    @BobJoe1803 Just ensure that all the tab-widgets inherit from a base-class that defines a default exit function. Common operations can go in the base implementation, and tab-widget classes can override it to add extra functionality. The signal-handler for currentChanged then just needs to do e.g. self.tabWidget.widget( self._prev_index).exitFunction(). Can't get much simpler than that. Commented Jun 15 at 8:31

1 Answer 1

1

Keeping track of the "previous" tab index is the only way.

In fact, that's exactly what QTabWidget (or, to be precise, its QTabBar) does: it maintains an internal "current index" property and eventually changes it if the requested one is different, then emits the currentChanged signal.

Since there is no way to access the previous index right before the new one is actually changed, you then need to store it on your own.

One possibility could involve a custom signal that emits the previous index, which you can then connect to a function that eventually calls the required function.

class CustomTabWidget(QTabWidget):
    _prevIndex = -1
    previousIndexChanged = pyqtSignal(int)
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.currentIndexChanged.connect(self.emitPrevIndex)

    def emitPrevIndex(self, index):
        if self._prevIndex != index:
            old = self._prevIndex
            self._prevIndex = index
            self.previousIndexChanged.emit(old)


def callExitFunction(index):
    widget = tabWidget.widget(index)
    if widget is not None:
        # call the exit function related to that widget

tabWidget.previousIndexChanged.connect(callExitFunction)

You need to be careful and aware about some important aspects, though; specifically:

  • if you allow the user to move tabs (or you move them programmatically);
  • if new tabs could be inserted before the current tab (using insertTab() instead of addTab()) at runtime;
  • if you allow the possibility of closing tabs, or you remove them (or the related widget is deleted) programmatically;

For all of the above, the _prevIndex attribute may probably become inappropriate or even unused, unless you take proper precautions considering what follows:

  • if the tab movement causes the current one to change its index (because a following tab is moved before it or a previous one is moved after the current), the _prevIndex won't correspond to the current anymore;
  • if one of the two moved tab is the current, currentChanged would be emitted even though no exit function should be called;
  • if a new tab is inserted before the current, _prevIndex will be off by one position;
  • the same happens if a tab before the current is removed (or the current one is), but currentChanged will also be emitted, trying to call the exit function either on a wrong widget, or a non existent one (if the current is the last);
  • if the current tab is internally being removed because the widget is deleted, it may cause an exception, depending on what the exit function does;

If you really need runtime/dynamic tab movement/deletion/insertion, you should consider further precautions, possibly adding proper updates to the _prevIndex attribute, and verifying widget existence/index.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.