尽管show()被调用,但插入的选项卡未显示在QTabWidget中

时间:2014-12-16 09:45:05

标签: python qt pyqt pyqt4

我在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_())

1 个答案:

答案 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()