Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Tab title goes in the wrong tab



  • Tab titles work just fine until you close a tab (any tab). After that, when you load a page, the title jumps to the wrong tab.
    I've been scratching my head over this for a while. Every tutorial online seems to have this same bug.
    Something messes up the indexing when you close a tab. I tried adding setCurrentIndex(index) to the close tab function, but it doesn't do anything.
    Is there any simple fix to this?

    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtWebEngineWidgets import *
    import sys
    
    
    class Page(QWebEnginePage):
        def __init__(self):
            super(QWebEnginePage, self).__init__()
    
    class Browser(QWebEngineView):
        def contextMenuEvent(self, event):
            self.menus = QMenu()
            action1 = QAction("Copy text", self)
            self.menus.addAction(action1)
    
    class Urlbar(QLineEdit):
        def contextMenuEvent(self, event):
            self.menus = QMenu()
            action1 = QAction("Copy", self)
            self.menus.addAction(action1)
    
    class MainWindow(QMainWindow):
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
            self.setMinimumHeight(450)
            self.setMinimumWidth(900)
    
            self.tabs = QTabWidget()
            self.setCentralWidget(self.tabs)
            self.tabs.currentChanged.connect(self.current_tab_changed)
            self.tabs.setTabsClosable(True)
            self.tabs.tabCloseRequested.connect(self.close_tab)
    
            toolbar = QToolBar()
            QToolBar.setContextMenuPolicy(self, Qt.NoContextMenu)
            toolbar.setIconSize(QSize(50, 44))
            toolbar.setMovable(False)
            self.addToolBar(toolbar)
    
            #add new tab button
            cornerw = QPushButton(self.tabs)
            self.tabs.setCornerWidget(cornerw, Qt.TopLeftCorner)
            cornerw.clicked.connect(self.add_new_tab)
    
            #address bar
            self.urlbar = Urlbar()
            toolbar.addWidget(self.urlbar)
            self.urlbar.returnPressed.connect(self.go_to_url)
    
            self.add_new_tab()
            self.show()
    
        def add_new_tab(self):
            index = self.tabs.count()
            browser = Browser()
            title = "New tab"
            self.tabs.addTab(browser, title)
            self.tabs.setCurrentIndex(index)
            page = Page()
            browser.setPage(page)
    
            browser.loadFinished.connect(lambda tabtitle, index=index, browser=browser:self.onLoadFinished(index, browser))
            browser.loadFinished.connect(lambda windowtitle, browser=browser:self.setWindowTitle(browser.page().title()))
            browser.urlChanged.connect(lambda url, browser=browser:self.update_urlbar_and_window(url, browser))
    
        def onLoadFinished(self, index, browser):
            self.tabs.setTabText(index, browser.page().title())
    
        def close_tab(self, index):
            if self.tabs.count() > 1:
                self.tabs.removeTab(index)
            return
    
        def go_to_url(self):
            url = QUrl.fromUserInput(self.urlbar.text()).toString()
            self.tabs.currentWidget().load(QUrl(url))
    
        def update_urlbar_and_window(self, url, browser):
            if browser != self.tabs.currentWidget():
                return
            self.setWindowTitle(self.tabs.currentWidget().page().title())
            self.urlbar.setText(url.toString())
            self.urlbar.setCursorPosition(0)
    
        def current_tab_changed(self, index):
            url = self.tabs.currentWidget().url()
            self.update_urlbar_and_window(url, index)
    
    
    app = QApplication(sys.argv)
    app.setApplicationName("Extreme Tabbing Action")
    window = MainWindow()
    app.exec_()
    


  • @Harborman said in Tab title goes in the wrong tab:

    browser.loadFinished.connect(lambda tabtitle, index=index, browser=browser:self.onLoadFinished(index, browser))

    If I'm not mistaken. You connect here with a lambda passing index. That is index during add_new_tab(). If later on you change tabs like remove or insert the original index at add time will be incorrect for passing to lambda slot.



  • I already started trying to create some kind of dict that collects information about used indexes and the amount of opened pages, for loops, etc...
    But could it really be this simple:

            browser.loadFinished.connect(lambda tabtitle:self.onLoadFinished(browser))
    
       def onLoadFinished(self, browser):
            current = self.tabs.currentWidget()
            i = self.tabs.indexOf(current)
            self.tabs.setTabText(i, browser.page().title())
    

    Yeah the lambda is still there but instead of passing the index and coming up with clever ways to update it, or keeping track of what's been opened and what's been closed I just refer to the index of the current widget when setting the tab title. So far it seems to have worked.

    EDIT: Seemed too simple to be truly functional. If the page loads for a long time and you change the current tab during the loading, the title will land in the tab you're on, not the tab where the signal came from. I overlooked this because I only used sample pages that loaded instantly.
    I can halfway fix this with something like

            if browser != self.tabs.currentWidget():
                return
    

    but in this case there's no title in any tab. How do I just force the title into the tab where the signal came from?



  • @Harborman
    Sorry, I don't understand all that you are saying. If I understand, all you need to do is pass the page-widget where the page has loaded or you want to set the title as a parameter in the signal -> slot, or find the page-widget in the slot if that works for you. The important thing is not to pass a tab index in the signal, where that index was fixed at tab creation time but is now incorrect due to tab deletion/insertion.



  • Here's my latest attempt, this seems to work:

       def add_new_tab(self):
            index = self.tabs.count()
            browser = Browser()
            title = "Empty tab"
            self.tabs.addTab(browser, title)
            self.tabs.setCurrentIndex(index)
    
            browser.loadFinished.connect(lambda tabtitle:self.on_load_finished(browser))
    
        def on_load_finished(self, browser):
            loadedpage = browser
            i = self.tabs.indexOf(loadedpage)
            self.tabs.setTabText(i, browser.page().title())
    


  • @Harborman
    This looks much better! Your lambda now passes the page as a parameter, and unlike your original index that does not change as you insert/delete other pages. Then you look up the page in the tabs during the slot to find it at that time.


Log in to reply