[英]PyQt5: How to Re-Dock back a floated QDockWidget via a QPushButton?
[英]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.