PyQt中QTabWidget的鼠标事件

5

我想在QTabWidget上检测鼠标中键单击事件。我本以为QWidget上会有与鼠标事件相关的信号,但我看到的都是方法。

我需要继承QTabWidget并重载相关方法才能做到我想要的吗?还是我漏掉了什么?

1个回答

9

您可以在 QTabWidget.tabBar() 返回的 QTabBar 上安装一个事件过滤器来接收和处理按下和释放事件,或者子类化 QTabBar 来重新定义 mousePressEventmouseReleaseEvent 并使用 QTabWidget.setTabBar() 方法替换 QTabWidgetQTabBar

  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
    
(如果您想知道为什么针对这样一个简单的任务需要这么多代码,那是因为点击被定义为在大致相同的位置进行按下事件和释放事件,因此按下的选项卡索引必须与释放的选项卡索引相同。)

+1 是为了展示如何使用按下和释放来实际复制点击信号。如果您没有使用旧和新标签索引来确定单击是否有效,则一般方法也是使用旧点和新点的曼哈顿长度来确定它是否在可接受范围内,以便称其为单击:http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qpoint.html#manhattanLength - jdi
确切地说,这正是我希望得到的回答。之前不知道还有事件过滤器这个功能。谢谢你提供如此详细和易懂的解释。 - Mathieson
@jdi:谢谢你的提示!我还在摸索这里的工作方式。否则我不会知道该怎么做。 - Mathieson
如果 object == self.tabWidget.tabBar(),那么这个表达式真的需要括号吗? - Daniel
@dmd 是的,应该可以。tabBar()是一个函数调用。 - alexisdm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接