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

9
我有一个扩展的主窗口,其中添加了一个QtGui.QTabWidget。我正在创建多个扩展自QtGui.QWidget的小部件,可以将其添加到选项卡窗口中并删除。
我想做的是有一个“弹出”按钮,使子部件从标签窗口中移除并提取为独立的窗口(还有一个“弹入”按钮将其放回到主窗口)。与Gmail中的Gtalk类似的概念。
请注意,如果我关闭主窗口,则其他“选项卡”或“窗口”也应关闭,并且我应该能够将所有窗口并排放置并同时显示和更新它们。 (我将显示几乎实时的数据)。
我是Qt的新手,但如果我没弄错的话,如果一个小部件没有父级,它会作为独立的窗口显示。这很有效,但我不知道如何“弹回”窗口。
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的想法呢?

2个回答

13

保留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_())

1
嗨@Avaris,那正是我想要的,只是在查看文档时似乎找不到它。这里程序流程也更清晰,所以感谢您提供的绝佳示例! :) - Laura Huysamen

0
在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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接