在pyQt5中,QDockWidget不再停靠双击



我在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中,双击总是在尝试切换其顶级状态之前检查dock小部件是否实际设置在有效的QMainWindow父级上。

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

唯一的解决方案是正确地检查双击,而这只能通过重写event()来实现,因为它是由dock小部件内部管理的,以防出现"双击";标题栏小部件";并且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中的内置类型:虽然不被禁止,但不应将其用作变量名

最新更新