如何跟踪可移动 QTab 的本地位置?

How to track the local position of a movable QTab?

我目前正在尝试设置边界,以便制表符不能超出我的 QTabBar 两端。默认情况下,只要将可移动选项卡拖出 QTabBar 的区域,它就会消失在空白中 - An example of the QTab being dragged outside of the QTabBar's Area.

这在大多数情况下都很好,但在视觉上我希望选项卡在到达 QTabBar 的边缘后完全停止移动。我试图通过 Qt 的事件系统来实现这个目标,目前只支持左边界。每当用户单击 QTab 时,我都会记录他的鼠标初始位置和当前选项卡未移动的位置和大小。然后,我使用这些值来确定如果用户向左移动鼠标,当前选项卡将在哪个 x 位置到达 QTabBar 的边缘。如果到达此位置,则会过滤事件以防止选项卡进一步移动。

    def eventFilter(self, source, event):
    if event.type() == QEvent.Type.MouseButtonPress:
        self.startingpos = event.x()
        self.tabOrigin = self.curTab.x()
        self.tabRoom = self.startingpos - self.tabOrigin

    if event.type() == QEvent.Type.MouseMove:
        if self.curIndex != self.tabs.currentIndex():
            self.curIndex = self.tabs.currentIndex()
            self.curTab = self.tabs.tabBar().tabRect(self.curIndex)

        if event.x() < self.tabRoom:
            return True
    return False

除非用户快速向左移动鼠标,否则此策略是有效的。这会导致移动选项卡在鼠标经过指定边界之前卡在鼠标的最后记录位置,然后到达 QTabBar 的边缘 - An example of the QTab getting stuck before reaching the left side of the QTabBar.

我不确定如何解决这个问题。我了解移动选项卡实际上与最初单击的选项卡不同。无论如何访问移动选项卡的位置并手动设置其位置?如果没有,任何有关如何解决此问题的建议都将不胜感激。

鼠标事件不是线性的,如果用户移动鼠标太快,它们会“跳过”像素。

问题是“移动选项卡”完全在内部实现,因此无法访问该选项卡(实际上,它是临时绘制在其余选项卡上的“假”小部件)。

一个可能的解决方案是检测当前按下的标签,获取鼠标相对于该标签的水平位置,检查移动是否超出限制(左边为0,右边为右边距的最后一个标签), 在此基础上合成一个新的鼠标事件,然后 post 该事件。

    def eventFilter(self, source, event):
        if (event.type() == event.MouseButtonPress and 
            event.button() == QtCore.Qt.LeftButton):
                tabRect = source.tabRect(source.tabAt(event.pos()))
                self.leftDistance = event.x() - tabRect.left()
                self.rightMargin = tabRect.right() - event.x()
                self.rightLimit = source.tabRect(self.tabs.count() - 1).right()
        elif (event.type() == event.MouseMove and 
            event.buttons() == QtCore.Qt.LeftButton):
                if event.x() - self.leftDistance < 0:
                    pos = QtCore.QPoint(self.leftDistance, event.y())
                    newEvent = QtGui.QMouseEvent(
                        event.type(), pos, 
                        event.button(), event.buttons(), 
                        event.modifiers())
                    QtWidgets.QApplication.postEvent(source, newEvent)
                    return True
                elif event.x() + self.rightMargin > self.rightLimit:
                    pos = QtCore.QPoint(
                        self.rightLimit - self.rightMargin, event.y())
                    newEvent = QtGui.QMouseEvent(
                        event.type(), pos, 
                        event.button(), event.buttons(), 
                        event.modifiers())
                    QtWidgets.QApplication.postEvent(source, newEvent)
                    return True
        return super().eventFilter(source, event)

请注意,eventFilter() 应该 始终 return 基本实现,否则在某些情况下您可能会遇到意外行为。