Search code examples
pythonpyqtpyqt5qtabwidget

How to add a new tab to QTabWidget


I have a QtTabWidget with 1 (or 2) widgets (my main page widget) hanging off of it like:

330     for i in range(1):
331         win = MainWindow()
332         tabs.addTab(win, QIcon('running.png'), "Test-%d" % i)
333     tabs.show()
334     print("tab count = %d" % tabs.count())

AFAIK, 'tabs' is now a parent to 'win'. I also have a tool bar with a "Add Tab" and "Remove Tab". The remove/quit handler is working and is like

254     # ----------------------- quitHandler() ------------------------
255     def quitHandler(self):
256         if ( self.parentWidget().count() == 1 ):
257             self.statusBar.setText('I am the last one, you can not kill me ....')
258             return
259         tab = self.parentWidget().currentWidget()
260         self.close()
261         self.parentWidget().removeWidget(tab)
262 

But my "Add Tab" handler written as

263     # ----------------------- newTabHandler() ------------------------
264     def newTabHandler(self):
265         count = self.parentWidget().count()
266         if ( count > 10 ):
267             self.statusBar.setText('I only support 10 tabs ....')
268             return
269         win = MainWindow()
270         self.parentWidget().addWidget(win)
271         self.parentWidget().show()
272         print(self.parentWidget().count())

is not rendering the new tab. But I see that tab count is increasing .. here is the log

medi@medi:~/proto/python/d1> ./utg
tab count = 1
2
3
4
5

Help is appreciated.

As requested, here is a minimal code to show the problem statement:

  1 #!/usr/bin/python3
  2 
  3 import sys
  4 import os
  5 
  6 from PyQt5 import (QtCore, QtWidgets, QtGui)
  7 from PyQt5.QtGui import (QIcon)
  8 from PyQt5.QtWidgets import (QMainWindow, QPushButton, QLabel, QLineEdit, QTextEdit)
  9 from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QVBoxLayout, QGroupBox, QGridLayou    t)
 10 from PyQt5.QtWidgets import (QFormLayout, QSizePolicy, QAction, QToolBar)
 11 from PyQt5.QtCore import (QSize, QProcess)
 12 
 13 class MainWindow(QMainWindow):
 14     def __init__(self):
 15         super().__init__()
 16         self.setWindowTitle('tabs mgmnt test')
 17         self.setGeometry(50, 50, 600, 600)
 18 
 19         self.toolbar = QToolBar('My Main Tool Bar')
 20         self.addToolBar(self.toolbar)
 21         newTabAct = QAction('New Tab', self)
 22         self.toolbar.addAction(newTabAct)
 23         newTabAct.triggered.connect(self.newTabHandler)
 24         
 25    # ----------------------- newTabHandler() ------------------------
 26     def newTabHandler(self):
 27         print("before new tab, tab-count = %d" % self.parentWidget().count() )
 28         win = MainWindow()
 29         self.parentWidget().addWidget(win)
 30         self.parentWidget().show()
 31         print("after new tab, tab-count = %d" % self.parentWidget().count() )
 32 
 33 # ================================= main() ==========================
 34 if (__name__ == "__main__"):
 35     app = QtWidgets.QApplication(sys.argv)
 36     tabs = QtWidgets.QTabWidget()
 37     win = MainWindow()
 38     tabs.addTab(win, "Tab-1" )
 39     tabs.show()
 40     sys.exit ( app.exec_() )
 41 

As seen, in main() and line 36 I create a QTabWidget and a window and hang the window to tabs.So I believe, 'tabs' is parent and 'win' is a child. Then the 'newTabHandler()' on line 26 should add another tab to tabs. But this method is an instance method of MainWindow and does not see 'tabs' which is local to main(). So I traverse the parent-child relation via parentWidget(). Also note that the print() statements on line 27 and 31 are reporting correct tab count. But I do not see the new tab rendered. Maybe I am missing a show() against some object. which I do on line 30. Yet no rendering of new tab and I only see one tab, the one created in main().


Solution

  • To understand the problem you must print the parentWidget() in newTabHandler:

    def newTabHandler(self):
        print(self.parentWidget())
    

    and you will notice that every time you try to add a tab you get:

    <PyQt5.QtWidgets.QStackedWidget object at 0x7f3e4e2680d0>
    <PyQt5.QtWidgets.QStackedWidget object at 0x7f3e4e2680d0>
    <PyQt5.QtWidgets.QStackedWidget object at 0x7f3e4e2680d0>
    ...
    

    So parentWidget() is not the QTabWidget but a QStackedWidget.

    Explanation:

    A QTabWidget is a QTabBar + QStackedWidget, and every time you add a widget using addTab() the widget is added to the QStackedWidget and a new tab is created in the QTabBar, so accordingly the parent of the widget is the QStackedWidget.

    Solution:

    Considering the above, the solution is to use the parentWidget() of the QStackedWidget which is the QTabWidget, or in the code that you provide as the QTabWidget is the window then use the window() method:

    def newTabHandler(self):
        tab_widget = self.parentWidget().parentWidget()
        #                QStackedWidget   QTabWidget
        # or
        # tab_widget = self.window()
        print(tab_widget)
        count = tab_widget.count()
        win = MainWindow()
        tab_widget.addTab(win, "Tab-{}".format(count + 1))