Как встроить пользовательский виджет в QTabBar при стыковке нескольких QDockWidget в PyQt6?

Я разрабатываю приложение на PyQt6, в котором использую несколько QDockWidget.
Когда эти QDockWidget стыкуются вместе, они автоматически создают вкладки в QTabBar.

Я хотел бы встроить пользовательский виджет, например, QPushButton, в QTabBar для каждой вкладки.
Я пробовал использовать метод setTabButton(), но виджет не отображается на вкладке, как ожидалось.


main.py:

from PyQt6.QtWidgets import (QApplication, QMainWindow, QDockWidget, QLabel, QPushButton, QTabBar, QTabWidget, QWidget)
from PyQt6.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # Создаем два QDockWidget
        dock1 = QDockWidget("Dock 1", self)
        dock2 = QDockWidget("Dock 2", self)

        # Добавляем простой виджет в QDockWidget
        dock1.setWidget(QLabel("Content of Dock 1"))
        dock2.setWidget(QLabel("Content of Dock 2"))

        # Добавляем QDockWidget в главное окно
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dock1)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dock2)

        # Стыкуем второй док виджет с первым
        self.tabifyDockWidget(dock1, dock2)

        # Пытаемся найти QTabBar и добавить пользовательский виджет
        tab_bar = self.findTabBar()

        if tab_bar:
            for index in range(tab_bar.count()):
                custom_widget = QPushButton(f"Button {index + 1}")
                tab_bar.setTabButton(index, QTabBar.ButtonPosition.LeftSide, custom_widget)

    def findTabBar(self):
        for widget in self.findChildren(QWidget):
            if isinstance(widget, QTabWidget):
                return widget.tabBar()
        return None

app = QApplication([])
window = MainWindow()
window.show()
app.exec()

Однако, виджеты в заголовках вкладок не появляются. Возможно, я что-то упускаю.

Как правильно встроить пользовательский виджет в заголовок вкладки в QTabBar?
Заранее спасибо за помощь!


Ответы (1 шт):

Автор решения: S. Nick

Можно попробовать, примерно так:

import sys
'''
from PyQt6.QtWidgets import (QApplication, QMainWindow, 
    QDockWidget, QLabel, QPushButton, QTabBar, QTabWidget, QWidget)
from PyQt6.QtCore import Qt
'''
from PyQt5.Qt import *


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.tab_bar = None                                       # +++

        # Создаем два QDockWidget
        self.dock1 = QDockWidget("Dock 1", self)
        self.dock1.dockLocationChanged.connect(self.dock_area)    # +++
        self.dock2 = QDockWidget("Dock 2", self)
        self.dock2.dockLocationChanged.connect(self.dock_area)    # +++

        # Добавляем простой виджет в QDockWidget
        self.dock1.setWidget(QLabel("Content of Dock 1"))
        self.dock2.setWidget(QLabel("Content of Dock 2"))

        # Добавляем QDockWidget в главное окно
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock1)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock2)

        # Стыкуем второй док виджет с первым
        self.tabifyDockWidget(self.dock1, self.dock2)

        # Пытаемся найти QTabBar и добавить пользовательский виджет
# +++   vvvv
        self.tab_bar = self.findTabBar()
        self.tab_bar_btn()                                          # +++
        
    def findTabBar(self):
        for widget in self.findChildren(QWidget):
# !!! --------------------------> vvvvvvv <----------------------------------
            if isinstance(widget, QTabBar):                         # !!! +++
                return widget                                       # +++
        return None

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    def tab_bar_btn(self):                                          # +++
        if self.tab_bar:
            for index in range(self.tab_bar.count()):
                tabText = self.tab_bar.tabText(index)
                custom_widget = QPushButton(f"Button {tabText[-1]}")
                custom_widget.clicked.connect(
                    lambda ch, ind=index, btn=custom_widget: 
                        self.btn_clicked(ind, btn))
                self.tab_bar.setTabButton(
                    index, 
                    QTabBar.ButtonPosition.LeftSide, 
                    custom_widget)

    def btn_clicked(self, ind, btn):                                # +++
        print(ind, btn.text())    

    def dock_area(self, _area):                                     # +++
        if self.tab_bar is None:
            return
            
        if self.tab_bar.count() == 2:
            widgets = self.tab_bar.children()
            for widget in widgets:
                if isinstance(widget, QPushButton):
                    widget.deleteLater()
            self.tab_bar_btn() 
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

введите сюда описание изображения

→ Ссылка