PyQt mouse events for QTabWidget
Asked Answered
C

1

5

I want to detect middle mouse clicks on a QTabWidget. I was expecting there to be a mouse event related signal on QWidget, but all I am seeing are methods.

Do I need to subclass the QTabWidget and then override said methods in order to do what I want, or am I missing something?

Chloechloette answered 25/2, 2012 at 7:24 Comment(0)
F
9

You can either install an event filter on the QTabBar (returned by QTabWidget.tabBar()) to receive and handle press and release events, or subclass QTabBar to redefine mousePressEvent and mouseReleaseEvent and replace the QTabBar of the QTabWidget with QTabWidget.setTabBar().

  1. Example using the event filter:

    class MainWindow(QMainWindow):
        def __init__(self):
            super(QMainWindow,self).__init__()
            self.tabWidget = QTabWidget(self)
            self.setCentralWidget(self.tabWidget)
            self.tabWidget.tabBar().installEventFilter(self)
            self.tabWidget.tabBar().previousMiddleIndex = -1           
    
        def eventFilter(self, object, event):
            if object == self.tabWidget.tabBar() and \
                event.type() in [QEvent.MouseButtonPress, 
                                 QEvent.MouseButtonRelease] and \
                event.button() == Qt.MidButton: 
                tabIndex = object.tabAt(event.pos())
                if event.type() == QEvent.MouseButtonPress:
                    object.previousMiddleIndex = tabIndex
                else:   
                    if tabIndex != -1 and tabIndex == object.previousMiddleIndex:
                        self.onTabMiddleClick(tabIndex)                    
                    object.previousMiddleIndex = -1                        
                return True               
            return False
    
        # function called with the index of the clicked Tab
        def onTabMiddleClick(self, index):
            pass
    
  2. Example using a QTabBar subclass:

    class TabBar(QTabBar):
        middleClicked = pyqtSignal(int)
    
        def __init__(self):
            super(QTabBar, self).__init__()
            self.previousMiddleIndex = -1
    
        def mousePressEvent(self, mouseEvent):
            if mouseEvent.button() == Qt.MidButton:
                self.previousIndex = self.tabAt(mouseEvent.pos())
            QTabBar.mousePressEvent(self, mouseEvent)
    
        def mouseReleaseEvent(self, mouseEvent):
            if mouseEvent.button() == Qt.MidButton and \
                self.previousIndex == self.tabAt(mouseEvent.pos()):
                self.middleClicked.emit(self.previousIndex)
            self.previousIndex = -1
            QTabBar.mouseReleaseEvent(self, mouseEvent)
    
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super(QMainWindow,self).__init__()
            self.tabWidget = QTabWidget(self)
            self.setCentralWidget(self.tabWidget)
    
            self.tabBar = TabBar()
            self.tabWidget.setTabBar(self.tabBar)
            self.tabBar.middleClicked.connect(self.onTabMiddleClick)
    
        # function called with the index of the clicked Tab
        def onTabMiddleClick(self, index):
            pass
    

(In case you wonder why there is so much code for such a simple task, a click is defined as a press event followed by a release event at roughly the same spot, so the index of the pressed tab has to be the same as the released tab).

Fredfreda answered 25/2, 2012 at 16:1 Comment(5)
+1 for showing how to actually replicate a click signal with the press and release. If you weren't using the old and new tab index to determine if the click is valid, the general approach is also to use the manhatten length of the old and new point to determine if its within an acceptable range to call it a click: riverbankcomputing.co.uk/static/Docs/PyQt4/html/…Sayette
Exactly the kind of answer I was hoping for. Wasn't aware of the event filter. Thanks for giving such a detailed and well explained response.Chloechloette
@jdi: Thanks for the tip! Still figuring out how things work around here. Wouldn't have known to do that otherwise.Chloechloette
if object == self.tabWidget.tabBar() ... should that really have parens on it?Vienne
@dmd yes, it should. tabBar() is a function call.Fredfreda

© 2022 - 2024 — McMap. All rights reserved.