如何从 PySide Qt 中的 tabWidget 弹出一个单独的窗口

Posted

技术标签:

【中文标题】如何从 PySide Qt 中的 tabWidget 弹出一个单独的窗口【英文标题】:How to pop out a separate window from a tabWidget in PySide Qt 【发布时间】:2013-02-14 10:31:48 【问题描述】:

我有一个扩展的主窗口,其中添加了QtGui.QTabWidget。我正在创建几个从QtGui.QWidget 扩展的小部件,我可以将它们添加和删除到选项卡小部件中。

我想做的是有一个“弹出”按钮,它会导致子小部件从选项卡小部件中删除并作为它自己的独立窗口出现(以及一个“弹出”按钮来放置它回到主窗口)。与 Gtalk-in-Gmail 的想法相同。 请注意,如果我关闭主窗口,其他“选项卡”或“窗口”也应该关闭,并且我应该能够并排放置所有窗口并让它们都可见并同时更新。 (我将显示近乎实时的数据)。

我是 Qt 的新手,但如果我没记错的话,如果 Widget 没有父级,它会独立出现。这可行,但我不知道如何将窗口“弹出”回。

class TCWindow(QtGui.QMainWindow): 
    .
    .
    .
    def popOutWidget(self, child):
        i = self.tabHolder.indexOf(child)
        if not i == -1:
             self.tabCloseRequested(i)
        self.widgets[i].setParent(None)
        self.widgets[i].show()

我的直觉告诉我,两者之间应该仍然存在父子关系。

有没有办法保留父级但仍然让窗口独立出现,还是我误解了 Qt 的风格?

否则,在孩子中创建一个变量来保存指向主窗口的链接(如self.parentalUnit = self.parent())是一个好主意还是一个hackish/kludgy的主意?

【问题讨论】:

【参考方案1】:

保持parent 不变。如果您删除parent,则关闭主窗口不会关闭“浮动”选项卡,因为它们现在是***窗口。 windowFlags 定义小部件是窗口还是子小部件。基本上,您需要在QtCore.Qt.WindowQtCore.Qt.Widget 之间交替使用

下面是一个小而完整的例子:

#!/usr/bin/env python
# -.- coding: utf-8 -.-
import sys
from PySide import QtGui, QtCore


class Tab(QtGui.QWidget):
    popOut = QtCore.Signal(QtGui.QWidget)
    popIn = QtCore.Signal(QtGui.QWidget)

    def __init__(self, parent=None):
        super(Tab, self).__init__(parent)

        popOutButton = QtGui.QPushButton('Pop Out')
        popOutButton.clicked.connect(lambda: self.popOut.emit(self))
        popInButton = QtGui.QPushButton('Pop In')
        popInButton.clicked.connect(lambda: self.popIn.emit(self))

        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(popOutButton)
        layout.addWidget(popInButton)


class Window(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__()

        self.button = QtGui.QPushButton('Add Tab')
        self.button.clicked.connect(self.createTab)
        self._count = 0
        self.tab = QtGui.QTabWidget()
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.button)
        layout.addWidget(self.tab)

    def createTab(self):
        tab = Tab()
        tab.setWindowTitle('%d' % self._count)
        tab.popIn.connect(self.addTab)
        tab.popOut.connect(self.removeTab)
        self.tab.addTab(tab, '%d' % self._count)
        self._count += 1

    def addTab(self, widget):
        if self.tab.indexOf(widget) == -1:
            widget.setWindowFlags(QtCore.Qt.Widget)
            self.tab.addTab(widget, widget.windowTitle())

    def removeTab(self, widget):
        index = self.tab.indexOf(widget)
        if index != -1:
            self.tab.removeTab(index)
            widget.setWindowFlags(QtCore.Qt.Window)
            widget.show()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    w = Window()
    w.show()

    sys.exit(app.exec_())

【讨论】:

嗨@Avaris,这正是我想要的正是,我在浏览文档时似乎找不到它。程序在这里的流程也更加清晰,所以感谢这个很好的例子! :) @LauraWentworth:我很高兴它有帮助:)。【参考方案2】:

在 Qt 中,布局对添加到布局的小部件拥有所有权,因此让它处理父级关系。 您可以创建另一个小部件(没有父小部件),该小部件将被隐藏,直到您按下弹出按钮并且按下它时,您从其原始布局中删除“弹出小部件”并将其添加到隐藏小部件的布局中。当按下弹出按钮时 - 将小部件返回到其原始布局。 要关闭此隐藏窗口,在关闭主窗口时,您需要将closeEvent(QCloseEvent* ev) 重新定义为类似这样的内容(对不起,对于 c++,但我敢打赌,在 python 中都是一样的):

void MainWindow::closeEvent(QCloseEvent* ev)

   dw->setVisible(false); // independent of mainwindow widget
   sw->setVisible(false); // independent of mainwindow widget
   QWidget::closeEvent(ev); //invoking close event after all the other windows are hidden

【讨论】:

以上是关于如何从 PySide Qt 中的 tabWidget 弹出一个单独的窗口的主要内容,如果未能解决你的问题,请参考以下文章

模型数据未更改时刷新视图(Qt/PySide/PyQt)?

Pyside (Qt) - 如何查询信号

识别 QT Qtabwidget 中的选项卡

使用 Pyside 的 Qt 树视图

从boost python模块中的pyside导入类?

PySide Qt 脚本不能从 Spyder 启动,但可以从 shell 运行