我在PyQt中有一个QTabWidget,可以撕掉标签并在关闭标签时重新连接它们。除了没有立即显示新附加的选项卡之外,它运行良好。显示一个空白窗口小部件,只有在当前选项卡更改后再更改后才会显示窗口小部件。
我搜索过StackOverflow,类似问题的答案指出添加新标签后需要调用添加的小部件show()
- 方法。我试过了,但新添加的标签仍未显示。
简化示例代码:
from PyQt4 import QtGui, QtCore
class DetachableTabWidget(QtGui.QTabWidget):
""" Subclass of QTabWidget which provides the ability to detach
tabs and making floating windows from them which can be reattached.
"""
def __init__(self, *args, **kwargs):
super(DetachableTabWidget, self).__init__(*args, **kwargs)
self.setTabBar(_DetachableTabBar())
def detach_tab(self, i):
""" Make floating window of tab.
:param i: index of tab to detach
"""
teared_widget = self.widget(i)
widget_name = self.tabText(i)
# Shift index to the left and remove tab.
self.setCurrentIndex(self.currentIndex() - 1 if self.currentIndex() > 0 else 0)
self.removeTab(i)
# Store widgets window-flags and close event.
teared_widget._flags = teared_widget.windowFlags()
teared_widget._close = teared_widget.closeEvent
# Make stand-alone window.
teared_widget.setWindowFlags(QtCore.Qt.Window)
teared_widget.show()
# Redirect windows close-event into reattachment.
teared_widget.closeEvent = lambda event: self.attach_tab(teared_widget, widget_name)
def attach_tab(self, widget, name):
""" Attach widget when receiving signal from child-window.
:param widget: :class:`QtGui.QWidget`
:param name: name of attached widget
"""
widget.setWindowFlags(widget._flags)
widget.closeEvent = widget._close
self.addTab(widget, name)
self.setCurrentWidget(widget)
self.currentWidget().show()
class _DetachableTabBar(QtGui.QTabBar):
def __init__(self, *args, **kwargs):
super(_DetachableTabBar, self).__init__(*args, **kwargs)
self._start_drag_pos = None
self._has_dragged = False
self.setMovable(True)
def mousePressEvent(self, event):
# Keep track of where drag-starts.
self._start_drag_pos = event.globalPos()
super(_DetachableTabBar, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
# If tab is already detached, do nothing.
if self._has_dragged:
return
# Detach-tab if drag in y-direction is large enough.
if abs((self._start_drag_pos - event.globalPos()).y()) >= QtGui.QApplication.startDragDistance()*8:
self._has_dragged = True
self.parent().detach_tab(self.currentIndex())
def mouseReleaseEvent(self, event):
self._has_dragged = False
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = QtGui.QMainWindow()
widget = DetachableTabWidget()
widget.addTab(QtGui.QLabel('Tab 1'), 'tab 1')
widget.addTab(QtGui.QLabel('Tab 2'), 'tab 2')
window.setCentralWidget(widget)
window.show()
sys.exit(app.exec_())
答案 0 :(得分:3)
似乎比接受QCloseEvent(默认行为)时,小部件隐藏在closeEvent处理程序的末尾。但是您对show()
的调用发生在处理程序结束之前。解决方案是忽略QCloseEvent。
...
teared_widget.closeEvent = lambda event: self.attach_tab(teared_widget, widget_name, event)
def attach_tab(self, widget, name, event):
""" Attach widget when receiving signal from child-window.
:param widget: :class:`QtGui.QWidget`
:param name: name of attached widget
:param event: close Event
"""
widget.setWindowFlags(widget._flags)
widget.closeEvent = widget._close
self.addTab(widget, name)
self.setCurrentWidget(widget)
event.ignore()