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

Posted

技术标签:

【中文标题】尽管调用了 show(),但插入的选项卡未在 QTabWidget 中显示【英文标题】:Inserted tabs not showing in QTabWidget despite show() called 【发布时间】:2014-12-16 09:45:04 【问题描述】:

我在 PyQt 中有一个 QTabWidget,它提供了撕下标签并在它们关闭时重新附加它们的可能性。它运行良好,只是新附加的选项卡没有立即显示。正在显示一个空白小部件,并且该小部件仅在当前选项卡已更改然后更改回来后才会显示。

我搜索过***,类似问题的答案指出,添加新标签后需要调用添加的小部件的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】:

看起来,当您接受 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()

【讨论】:

以上是关于尽管调用了 show(),但插入的选项卡未在 QTabWidget 中显示的主要内容,如果未能解决你的问题,请参考以下文章

卡未在引导程序 4 中居中 [重复]

引导导航选项卡未加载正确的页面

默认选项卡未将第一个选项卡显示为已选中

选项卡中的顺风选项卡未按预期工作

片段选项卡未使用所有空间

React 选项卡未出现在 chrome 开发人员工具中