pythonqtpyside

How to pop out a separate window from a tabWidget in PySide Qt


I have an extended main window with a QtGui.QTabWidget added to it. I am creating several widgets extended from QtGui.QWidget which I can add and remove to the tab widget.

What I would like to do is have a "pop-out" button that causes the child widget to be removed from the tab widget and come up as it's own independent window (and a "pop-in" button to put it back into the main window). The same sort of idea as Gtalk-in-Gmail has. Note that if I close the main window, the other "tabs" or "windows" should also close, and I should be able to put all the windows side-by-side and have them all visible and updating at the same time. (I will be displaying near-realtime data).

I am new to Qt, but if I'm not mistaken, if a Widget has no parent it comes up independently. This works, but I then have no idea how I could "pop" the window back in.

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

My gut says that there should still be a parent/child relationship between the two.

Is there a way to keep the parent but still have the window come up independently, or am I misunderstanding Qt's style?

Otherwise, would creating a variable in the child to hold a link to the main window (like self.parentalUnit = self.parent()) be a good idea or a hackish/kludgy idea?


Solution

  • Leave the parent as is. If you remove the parent, then closing main window won't close 'floating' tabs, since they are now top-level windows. windowFlags defines if a widget is window or a child widget. Basically, you need to alternate between QtCore.Qt.Window and QtCore.Qt.Widget

    Below is a small but complete example:

    #!/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_())