I'd like to have a "new tab" button much like Chrome or Firefox has for my QMdiArea.
I can make a button or menu item somewhere that adds a new subdocument to the MDI thing, but how can I make it a visually appealing tiny tab with a "+" as label? Alternatively, I would be happy enough with a QTabWidget with such a button.
I know that question is outdated, but some time ago I was looking for ready-to-use implementation of feature you requested. I digged a bit and implement this for Qt 5 -- take a look at repo.
Main idea is to do:
// Create button what must be placed in tabs row
QToolButton *tb = new QToolButton();
tb->setText("+");
// Add empty, not enabled tab to tabWidget
tabWidget->addTab(new QLabel("Add tabs by pressing \"+\""), QString());
tabWidget->setTabEnabled(0, false);
// Add tab button to current tab. Button will be enabled, but tab -- not
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, tb);
You will have to write your own class for the QTabBar. The plus button can be added by using absolute positioning.
I have some code here for PySide; it should give you the basic idea.
class TabBarPlus(QtGui.QTabBar):
    """Tab bar that has a plus button floating to the right of the tabs."""
    plusClicked = QtCore.Signal()
    def __init__(self):
        super().__init__()
        # Plus Button
        self.plusButton = QtGui.QPushButton("+")
        self.plusButton.setParent(self)
        self.plusButton.setFixedSize(20, 20)  # Small Fixed size
        self.plusButton.clicked.connect(self.plusClicked.emit)
        self.movePlusButton() # Move to the correct location
    # end Constructor
    def sizeHint(self):
        """Return the size of the TabBar with increased width for the plus button."""
        sizeHint = QtGui.QTabBar.sizeHint(self) 
        width = sizeHint.width()
        height = sizeHint.height()
        return QtCore.QSize(width+25, height)
    # end tabSizeHint
    def resizeEvent(self, event):
        """Resize the widget and make sure the plus button is in the correct location."""
        super().resizeEvent(event)
        self.movePlusButton()
    # end resizeEvent
    def tabLayoutChange(self):
        """This virtual handler is called whenever the tab layout changes.
        If anything changes make sure the plus button is in the correct location.
        """
        super().tabLayoutChange()
        self.movePlusButton()
    # end tabLayoutChange
    def movePlusButton(self):
        """Move the plus button to the correct location."""
        # Find the width of all of the tabs
        size = sum([self.tabRect(i).width() for i in range(self.count())])
        # size = 0
        # for i in range(self.count()):
        #     size += self.tabRect(i).width()
        # Set the plus button location in a visible area
        h = self.geometry().top()
        w = self.width()
        if size > w: # Show just to the left of the scroll buttons
            self.plusButton.move(w-54, h)
        else:
            self.plusButton.move(size, h)
    # end movePlusButton
# end class MyClass
class CustomTabWidget(QtGui.QTabWidget):
    """Tab Widget that that can have new tabs easily added to it."""
    def __init__(self):
        super().__init__()
        # Tab Bar
        self.tab = TabBarPlus()
        self.setTabBar(self.tab)
        # Properties
        self.setMovable(True)
        self.setTabsClosable(True)
        # Signals
        self.tab.plusClicked.connect(self.addTab)
        self.tab.tabMoved.connect(self.moveTab)
        self.tabCloseRequested.connect(self.removeTab)
    # end Constructor
# end class CustomTabWidget
Why not make a button out of the last tab of your QTabWidget ? Just create the last tab with a '+' symbol on it and use the currentChanged event.
class Trace_Tabs(QTabWidget):
    def __init__(self):
        QTabWidget.__init__(self)       
        self._build_tabs()
    def _build_tabs(self):
        self.setUpdatesEnabled(True)
        self.insertTab(0,QWidget(), "Trace" )
        self.insertTab(1,QWidget(),'  +  ') 
        self.currentChanged.connect(self._add_trace) 
    def _add_trace(self, index):    
        if index == self.count()-1 :    
            '''last tab was clicked. add tab'''
            self.insertTab(index, QWidget(), "Trace %d" %(index+1)) 
            self.setCurrentIndex(index)
if __name__ == '__main__':    
    app = QApplication([])    
    tabs = Trace_Tabs()
    tabs.show()    
    app.exec_()
There's a special method for this:
void QTabWidget::setCornerWidget(QWidget *widget, Qt::Corner corner = Qt::TopRightCorner)
I use it like this:
QIcon icon = QIcon::fromTheme(QLatin1String("window-new"));
QToolButton *btn = new QToolButton();
btn->setIcon(icon);
connect(btn, &QAbstractButton::clicked, this, &App::OpenNewTab);
tab_widget_->setCornerWidget(btn, Qt::TopRightCorner);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With