QTabBar Indexing is wrong for right mouse click


#1

Hi all, I am trying to grab ahold of the mouse position + right mouse click on QTabBar where it will pops up a message to User if they want to remove the said tab.

(Pardon the vague design) This is what my QTabBar looks like:
| + | food | snacks | drinks |

However, in my following code, whenever I tried to print out the index as I do a right-mouse click on the tabs, the returned index value is wrong.
It seems to have taken into account of the ‘+’ button as it is indicating as index 0 where index 0 should actually starts from the ‘food’ tab onwards.

Here is my code:

class MyWin(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MyWin, self).__init__()
        central_widget = QtGui.QWidget()
        self.setCentralWidget(central_widget)
        vlay = QtGui.QVBoxLayout(central_widget)
        hlay = QtGui.QHBoxLayout()
        vlay.addLayout(hlay)
        vlay.addStretch()

        self.add_button = QtGui.QToolButton()
        self.tab_bar = QtGui.QTabBar(self)
        self.add_button.setIcon(QtGui.QIcon('add.png'))
        self.add_button.setMenu(self.set_menu())
        self.add_button.setPopupMode(QtGui.QToolButton.InstantPopup)

        self.tab_bar.setTabButton(
            0,
            QtGui.QTabBar.ButtonPosition.RightSide,
            self.add_button
        )
        hlay.addWidget(self.add_button)
        hlay.addWidget(self.tab_bar)

    def set_menu(self):
        menu_options = ['food', 'drinks', 'snacks']
        qmenu = QtGui.QMenu(self.add_button)
        for opt in menu_options:
            qmenu.addAction(opt, partial(self.set_new_tab, opt))
        qmenu.addAction
        return qmenu

    def set_new_tab(self, opt):
        self.tab_bar.addTab(opt)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.RightButton:
            index = self.tab_bar.tabAt(event.pos())
            print index
        else:
            super(MyWin, self).mousePressEvent(event)


my_win = MyWin()
my_win.show()

Appreciate for any insights and many thanks in advance for any response!


#2

Hi,

I’m using PySide2 (from your code it looks like is PySide) so maybe is different…
So I did’t really found why you are getting the wrong index…

But I did something similar some time ago in a little different way… maybe this will help anyway…

from PySide2 import QtCore, QtGui, QtWidgets
import maya.cmds as cmds


class TabbedGuy(QtWidgets.QWidget):

    def __init__(self):
        super(TabbedGuy, self).__init__()

        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)

        self.tabs = QtWidgets.QTabWidget()
        self.tabs.setTabsClosable(True)

        layout.addWidget(self.tabs)

        # Add a button for adding tabs
        #
        self.add_button = QtWidgets.QPushButton('+')
        self.tabs.setCornerWidget(self.add_button, QtCore.Qt.TopLeftCorner)
        self.add_button.show()

        self.add_button.clicked.connect(self.addTab)
        self.tabs.tabCloseRequested.connect(self.closeTab)
        
        self.addTab('default')

    def closeTab(self, index):
        print 'requested to close', index
        if index != 0:
            self.tabs.removeTab(index)


    def addTab(self, tab_name=None):

        num_tabs = self.tabs.count()
        if not tab_name:
            tab_name = 'default_{}'.format(num_tabs)

        self.tabs.addTab(QtWidgets.QWidget(), tab_name)
        
        
win = TabbedGuy()
win.show()

#3

Hi Kos, thank you for your reply.

Even so, I would still like to find out what is exactly wrong with my code though, as it is causing issues with my right-click mouse menu.

Adding on, for my code I am only utilizing the QTabBar as I am trying to incorporate a ‘double-tiered’ tabs, something as follows:

 | + | food | snacks | drinks |
 | bread | rice | + |
 |                                         |
 |                                         |

where the bottom part is creating with both QTabWidget and QTabBar


#4

Hi,

I’ve checked what was going on.
So basically the event.pos() was giving you the “wrong coordinates” since it was on the parent widget.
The tabAt wants the coordinates in is own widget space, so rather than calculating the offset that can be tricky I’ve just subclassed the tab widget.
Now the tab is printed correctly

from PySide2 import QtCore, QtGui, QtWidgets
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
from functools import partial
import maya.cmds as cmds

class SpecialTab(QtWidgets.QTabBar):
    
    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.RightButton:
            index = self.tabAt(event.pos())
            print index
        else:
            super(SpecialTab, self).mousePressEvent(event)    
    

class MyWin(MayaQWidgetDockableMixin, QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MyWin, self).__init__()
        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        vlay = QtWidgets.QVBoxLayout(central_widget)
        hlay = QtWidgets.QHBoxLayout()
        vlay.addLayout(hlay)
        vlay.addStretch()

        self.add_button = QtWidgets.QToolButton()
        self.tab_bar = SpecialTab()
        self.add_button.setIcon(QtGui.QIcon('add.png'))
        self.add_button.setMenu(self.set_menu())
        self.add_button.setPopupMode(QtWidgets.QToolButton.InstantPopup)

        self.tab_bar.setTabButton(
            0,
            QtWidgets.QTabBar.ButtonPosition.RightSide,
            self.add_button
        )
        hlay.addWidget(self.add_button)
        hlay.addWidget(self.tab_bar)

    def set_menu(self):
        menu_options = ['food', 'drinks', 'snacks']
        qmenu = QtWidgets.QMenu(self.add_button)
        for opt in menu_options:
            qmenu.addAction(opt, partial(self.set_new_tab, opt))
        qmenu.addAction
        return qmenu

    def set_new_tab(self, opt):
        self.tab_bar.addTab(opt)


my_win = MyWin()
my_win.show()

#5

Hi Kos,

Many thanks for replying back. Is there a reason as to why you are using MayaQWidgetDockableMixin? Trying to get my head around it :slight_smile:


#6

There are 2 reasons for using that class:

  1. your window will not disappear if you click on the maya ui
  2. you can make it dockable

It’s the suggested way in the maya doc.
You can also parent to the maya UI, but that class already does it for you.