繁体   English   中英

QDockWidget 不再停靠在 pyQt5 中双击

[英]QDockWidget does not dock any longer on doubleclick in pyQt5

我在 pyQt4 中有一个解决方案,可以使用 QDockWidgets 和下面的代码将选项卡从/到 QTabWidget 取消停靠。 浮动一个选项卡后,双击QDockWidget的标题栏获得重新停靠。 但它在 pyQt5 中不再起作用(双击似乎没有触发 topLevelChanged 事件)。

为什么?

如何修复它并恢复正确的重新对接行为?

文档中在哪里解释了这种行为变化?

谢谢你的帮助。

import sys
try:
      from PyQt5.QtCore import QEvent
      from PyQt5.QtWidgets import QApplication, QMainWindow, QDockWidget, QTabWidget, QLabel
except:
      from PyQt4.QtCore import QEvent
      from PyQt4.QtGui  import QApplication, QMainWindow, QDockWidget, QTabWidget, QLabel


class DockToTabWidget(QDockWidget):

    def __init__(self, title, parent=0):
        QDockWidget.__init__(self, title, parent)
        self._title = title
        self.topLevelChanged.connect(self.dockToTab)

    def dockToTab(self):
        if not self.isFloating():
            self.parent().addTab(self.widget(), self._title)
            self.close()
            del self


class TabWidgetWithUndocking(QTabWidget):

    def __init__(self):
        super(TabWidgetWithUndocking, self).__init__()
        self.tabBar().installEventFilter(self)

    def eventFilter(self, object, event):
        if object == self.tabBar():
            if event.type() == QEvent.MouseButtonDblClick:
                pos = event.pos()
                tabIndex = object.tabAt(pos)
                title = self.tabText(tabIndex)
                widget = self.widget(tabIndex)
                self.removeTab(tabIndex)
                dockWidget = DockToTabWidget(title, parent=self)
                dockWidget.setFeatures(QDockWidget.AllDockWidgetFeatures)
                dockWidget.setWidget(widget)
                dockWidget.setFloating(True)
                dockWidget.move(self.mapToGlobal(pos))
                dockWidget.show()
                return True
            return False

    def tabClose(self, index):
        self.removeTab(index)

qApp = QApplication([])
qApp.setQuitOnLastWindowClosed(True)
sys.excepthook = sys.__excepthook__
main = QMainWindow()
main.setWindowTitle('Main')
twu = TabWidgetWithUndocking()
for i in range(2):
    twu.addTab(QLabel('tab %i' % i), 'tab %i' % i)
main.setCentralWidget(twu)
main.show()
qApp.exec_()

我不记得 Qt4 的实现,但是在 Qt5 中,双击总是检查停靠小部件是否实际设置在有效的 QMainWindow 父级上,然后再尝试切换其顶级 state。

您没有添加 QDockWidget,也没有使用 QMainWindow,因此永远不会发出信号。 这在某些情况下也会造成问题,因为它会阻止正确处理鼠标事件以允许拖动停靠小部件。

唯一的解决方案是正确检查双击,这只能通过覆盖event()来实现,因为它是由停靠小部件在内部管理的,以防设置“标题栏小部件”,并且永远不会调用mouseDoubleClickEvent

原始代码的以下编辑也适用于 PyQt4。

class DockToTabWidget(QDockWidget):
    attachRequested = pyqtSignal(QWidget, str)
    def __init__(self, title, widget):
        QDockWidget.__init__(self, title, widget.window())
        self.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.setWidget(widget)
        self.setFloating(True)

        floatButton = self.findChild(QAbstractButton, 'qt_dockwidget_floatbutton')
        floatButton.clicked.connect(self.attach)

    def attach(self):
        self.attachRequested.emit(self.widget(), self.windowTitle())
        self.deleteLater()

    def event(self, event):
        if (
            event.type() == event.MouseButtonDblClick 
            and event.button() == Qt.LeftButton
        ):
            opt = QStyleOptionDockWidget()
            self.initStyleOption(opt)
            if event.pos() in opt.rect:
                self.attach()
                return True
        return super().event(event)


class TabWidgetWithUndocking(QTabWidget):
    def __init__(self):
        super(TabWidgetWithUndocking, self).__init__()
        self.tabBar().installEventFilter(self)

    def eventFilter(self, obj, event):
        if obj == self.tabBar():
            if event.type() == QEvent.MouseButtonDblClick:
                pos = event.pos()
                tabIndex = obj.tabAt(pos)
                title = self.tabText(tabIndex)
                widget = self.widget(tabIndex)
                self.removeTab(tabIndex)
                dockWidget = DockToTabWidget(title, widget)
                dockWidget.attachRequested.connect(self.attachDock)
                dockWidget.move(self.mapToGlobal(pos))
                dockWidget.show()
                return True
            return False

    def attachDock(self, widget, title):
        self.setCurrentIndex(self.addTab(widget, title))

注意: object是 Python 中的内置类型:虽然没有被禁止,但不应将其用作变量名。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM