9

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?

Laura Huysamen
  • 398
  • 3
  • 9

2 Answers2

13

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_())
Avaris
  • 35,883
  • 7
  • 81
  • 72
  • 1
    Hi @Avaris, that is _exactly_ what I wanted, I just couldn't seem to find it when I was looking through the docs. It's also much clearer how the program flows here, so thanks for the great example! :) – Laura Huysamen Feb 14 '13 at 11:58
0

In Qt, layout takes ownership over the widgets that are added to layout, so let it handle parentship. You can create another widget (with no parent) which will be hidden until you press pop-out button and when it is pressed, you remove "pop-out widget" from its original layout and add it to layout of the hidden widget. And when pop-in button pressed - return widget to it's original layout. To close this hidden window, when closing main window, you will need to redefine closeEvent(QCloseEvent* ev) to something like this (sorry for c++, but i bet, in python it's all the same):

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
}
Shf
  • 3,463
  • 2
  • 26
  • 42