From ba0f8818bbd5b685708b1ca715e6a21c161f81a4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 11 Feb 2025 13:34:56 +0300 Subject: [PATCH] =?UTF-8?q?chore:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8F=20start=5Fwidget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gui/main_gui.py | 24 +-- src/gui/start_widget.py | 465 +++++++++++++++++++++++++--------------- 2 files changed, 300 insertions(+), 189 deletions(-) diff --git a/src/gui/main_gui.py b/src/gui/main_gui.py index 33f4b46..7ef654b 100644 --- a/src/gui/main_gui.py +++ b/src/gui/main_gui.py @@ -54,9 +54,9 @@ class MainWindow(BaseMainWindow): self._init_menu() self._init_status_bar() start_widget = StartWidget() - start_widget.seeking_mode_btn.clicked.connect(self._init_seekingUI) - start_widget.raport_mode_btn.clicked.connect(self._init_raportUI) - start_widget.client_mode_btn.clicked.connect(self._init_client_UI) + start_widget.btn_scanning.clicked.connect(self._init_seekingUI) + start_widget.btn_report.clicked.connect(self._init_raportUI) + start_widget.btn_client.clicked.connect(self._init_client_UI) self.setCentralWidget(start_widget.get_widget()) def _init_settings(self) -> None: @@ -67,10 +67,10 @@ class MainWindow(BaseMainWindow): def _init_menu(self) -> None: self.menu = CustomMenuBar(self.sysSettings, self.repSettings, self.operSettings, self.filterSettings) - self.menu.seeking_action.triggered.connect(self._init_seekingUI) - self.menu.raport_action.triggered.connect(self._init_raportUI) - self.menu.client_action.triggered.connect(self._init_client_UI) - self.menu.view_settings.triggered.connect(lambda: self._on_tab_changed(0)) + self.menu.action_scanning.triggered.connect(self._init_seekingUI) + self.menu.action_report.triggered.connect(self._init_raportUI) + self.menu.action_client.triggered.connect(self._init_client_UI) + self.menu.action_view_settings.triggered.connect(lambda: self._on_tab_changed(0)) self.menu.setup(self) def _init_status_bar(self) -> None: @@ -102,8 +102,8 @@ class MainWindow(BaseMainWindow): self._clear() self._set_mode(1) raport_widget = RaportWidget(self._tab_widget) - raport_widget.open_file_btn.clicked.connect(self._open_file) - raport_widget.save_screen_btn.clicked.connect(self._save_plots) + raport_widget.btn_open_file.clicked.connect(self._open_file) + raport_widget.btn_save_state.clicked.connect(self._save_plots) self.setCentralWidget(raport_widget.get_widget()) def _init_seekingUI(self) -> None: @@ -117,9 +117,9 @@ class MainWindow(BaseMainWindow): self._set_mode(3) client_widget = ClientAnalyzerWidget(self._tab_widget) #TODO: привязать действия к кнопкам - client_widget.open_folder_btn.clicked.connect(self._open_folder) - client_widget.save_screen_btn.clicked.connect(self._save_plots) - client_widget.build_TCW_btn.clicked.connect(self._build_TCW_for_client) + client_widget.btn_open_folder.clicked.connect(self._open_folder) + client_widget.btn_save_state.clicked.connect(self._save_plots) + client_widget.btn_calc_tcw.clicked.connect(self._build_TCW_for_client) self.setCentralWidget(client_widget.get_widget()) def _build_TCW_for_client(self): diff --git a/src/gui/start_widget.py b/src/gui/start_widget.py index 5179b61..3135194 100644 --- a/src/gui/start_widget.py +++ b/src/gui/start_widget.py @@ -1,11 +1,9 @@ from datetime import datetime as dt -from PyQt5.QtWidgets import (QWidget, QPushButton, - QMenuBar, QHBoxLayout, - QVBoxLayout, QLabel, - QDockWidget, QTabWidget, - QProgressBar, QAction, - QMainWindow, QGridLayout) +from PyQt5.QtWidgets import ( + QWidget, QPushButton, QMenuBar, QHBoxLayout, QVBoxLayout, QLabel, + QDockWidget, QTabWidget, QProgressBar, QAction, QMainWindow, QGridLayout +) from PyQt5.QtGui import QIcon from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QSizePolicy as QSP @@ -16,79 +14,125 @@ from base.base import PlotItems class StartWidget(QWidget): + """ + Виджет выбора режима работы приложения. + + Содержит кнопки для перехода в различные режимы: + - Сканирование папки в реальном времени + - Редактор отчётов + - Обработка клиентских трейсов + """ def __init__(self) -> None: super().__init__() self._build_main_layout() def get_widget(self) -> QWidget: + """ + Возвращает текущий виджет. + """ return self def _build_main_layout(self) -> None: - self.resize(800,800) - self.seeking_mode_btn = QPushButton("Real time folder scanning") - self.seeking_mode_btn.setFixedWidth(350) - self.raport_mode_btn = QPushButton("Raport editor") - self.raport_mode_btn.setFixedWidth(350) - self.client_mode_btn = QPushButton("Client trace processor") - self.client_mode_btn.setFixedWidth(350) + """ + Строит макет виджета с заголовком и кнопками выбора режима. + """ + self.resize(800, 800) + # Создаем кнопки для различных режимов работы + self.btn_scanning = QPushButton("Real time folder scanning") + self.btn_scanning.setFixedWidth(350) + self.btn_report = QPushButton("Raport editor") + self.btn_report.setFixedWidth(350) + self.btn_client = QPushButton("Client trace processor") + self.btn_client.setFixedWidth(350) + + # Размещение кнопок в горизонтальном макете button_layout = QHBoxLayout() button_layout.setSpacing(2) - button_layout.addWidget(self.seeking_mode_btn) - button_layout.addWidget(self.raport_mode_btn) - button_layout.addWidget(self.client_mode_btn) - button_widget = QWidget() - button_widget.setLayout(button_layout) + button_layout.addWidget(self.btn_scanning) + button_layout.addWidget(self.btn_report) + button_layout.addWidget(self.btn_client) + button_container = QWidget() + button_container.setLayout(button_layout) - mainLayout = QVBoxLayout() - label = QLabel("Select work mode") - label.setStyleSheet( + # Создаем основной вертикальный макет с заголовком и кнопками + main_layout = QVBoxLayout() + title_label = QLabel("Select work mode") + title_label.setStyleSheet( """QLabel{ color: #ffffff; font-size: 40px; font-weight: bold; font-family: "Segoe UI", sans-serif; }""" - ) - mainLayout.addWidget(label, alignment=Qt.AlignCenter) - mainLayout.addWidget(button_widget) - self.setLayout(mainLayout) - + ) + main_layout.addWidget(title_label, alignment=Qt.AlignCenter) + main_layout.addWidget(button_container) + self.setLayout(main_layout) + class CustomStatusBar(QWidget): + """ + Кастомный виджет для статус-бара, отображающий режим, заметку и прогресс. + """ def __init__(self) -> None: super().__init__() self._build_status_bar() def get_widget(self) -> QWidget: + """ + Возвращает виджет статус-бара. + """ return self - - def set_mode(self, msg:str = '') -> None: - if not isinstance(msg, str): msg = str(msg) + + def set_mode(self, msg: str = '') -> None: + """ + Устанавливает текст режима в статус-баре. + + :param msg: Сообщение для отображения. + """ + if not isinstance(msg, str): + msg = str(msg) self._mode_label.setText(msg) self._mode_label.adjustSize() - def set_note(self, msg:str = '') -> None: - if not isinstance(msg, str): msg = str(msg) + def set_note(self, msg: str = '') -> None: + """ + Устанавливает текст заметки в статус-баре. + + :param msg: Сообщение для отображения. + """ + if not isinstance(msg, str): + msg = str(msg) self._note_label.setText(msg) self._note_label.adjustSize() - def set_progress(self, percent:int = 0) -> None: - if not isinstance(percent, int): percent = 0 - elif percent < 0: percent = 0 - elif percent > 100: percent = 100 + def set_progress(self, percent: int = 0) -> None: + """ + Устанавливает значение прогресс-бара. + + :param percent: Значение прогресса (от 0 до 100). + """ + if not isinstance(percent, int): + percent = 0 + elif percent < 0: + percent = 0 + elif percent > 100: + percent = 100 self._progress_bar.setValue(percent) - def _build_status_bar(self) -> None: - # Создание пользовательского виджета для StatusBar - note_layout = QHBoxLayout() - note_layout.setContentsMargins(10, 1, 10, 1) - note_layout.setSpacing(15) # Устанавливаем расстояние между элементами - - # Создание QLabel и QProgressBar + """ + Создает и настраивает компоненты статус-бара. + """ + # Создаем горизонтальный макет с отступами и промежутками + layout = QHBoxLayout() + layout.setContentsMargins(10, 1, 10, 1) + layout.setSpacing(15) + + # Инициализируем компоненты статус-бара self._mode_label = QLabel() self._note_label = QLabel() self._progress_bar = QProgressBar() @@ -98,106 +142,141 @@ class CustomStatusBar(QWidget): self._progress_bar.setMaximumHeight(10) self._progress_bar.setTextVisible(False) - # Установка политики размеров + # Устанавливаем политику размеров для компонентов self._mode_label.setSizePolicy(QSP.Policy.Preferred, QSP.Policy.Preferred) self._note_label.setSizePolicy(QSP.Policy.MinimumExpanding, QSP.Policy.Preferred) self._progress_bar.setSizePolicy(QSP.Policy.Fixed, QSP.Policy.Preferred) - - # Добавление виджетов в макет - note_layout.addWidget(self._progress_bar) - note_layout.addWidget(self._note_label) - note_layout.addStretch(1) - note_layout.addWidget(self._mode_label) - self.setLayout(note_layout) + # Добавляем компоненты в макет + layout.addWidget(self._progress_bar) + layout.addWidget(self._note_label) + layout.addStretch(1) + layout.addWidget(self._mode_label) + + self.setLayout(layout) self.setSizePolicy(QSP.Policy.Expanding, QSP.Policy.Preferred) class CustomTabWidget(QTabWidget): + """ + Кастомный виджет-вкладка. - def __init__ (self): + Позволяет создавать вкладки с виджетом графика и закрывать их. + """ + + def __init__(self): super().__init__() self._build_tab_widget() - + def get_widget(self) -> QWidget: + """ + Возвращает виджет. + """ return self def _build_tab_widget(self) -> None: + """ + Настраивает виджет вкладок: включает возможность закрытия вкладок. + """ self.setTabsClosable(True) self.tabCloseRequested.connect(self.close_tab) - - #TODO: переписать обмен данными, засунуть ссылки куда-то еще - def create_tab(self, plot_widget:QWidget) -> None: - plot_items:PlotItems = plot_widget.property("pyqt_container") - tab = QWidget() - tab.setProperty("reg_items", plot_items.regions) - tab.setProperty("curve_items", plot_items.curves) - tab.setProperty("qt_items", plot_items.qt_items) - grid = QGridLayout() - grid.addWidget(plot_widget) - tab.setLayout(grid) - self.addTab(tab, "SF_trace_" + dt.now().strftime('%Y_%m_%d-%H_%M_%S')) - self.setCurrentWidget(tab) - def close_tab(self, index:int) -> None: + def create_tab(self, plot_widget: QWidget) -> None: + """ + Создает новую вкладку с виджетом графика. + + Извлекает из виджета необходимые данные, сохраняет их в свойствах вкладки. + + :param plot_widget: Виджет, содержащий график. + """ + # Извлекаем объект PlotItems, сохранённый в свойстве виджета + plot_items: PlotItems = plot_widget.property("pyqt_container") + new_tab = QWidget() + new_tab.setProperty("reg_items", plot_items.regions) + new_tab.setProperty("curve_items", plot_items.curves) + new_tab.setProperty("qt_items", plot_items.qt_items) + grid_layout = QGridLayout() + grid_layout.addWidget(plot_widget) + new_tab.setLayout(grid_layout) + tab_label = "SF_trace_" + dt.now().strftime('%Y_%m_%d-%H_%M_%S') + self.addTab(new_tab, tab_label) + self.setCurrentWidget(new_tab) + + def close_tab(self, index: int) -> None: + """ + Закрывает вкладку по заданному индексу. + + :param index: Индекс вкладки для закрытия. + """ if self.count() > index and index >= 0: self.removeTab(index) class CustomMenuBar(QMenuBar): + """ + Кастомное главное меню с док-виджетами для различных настроек. + """ - def __init__(self, - operSettings:OperatorSettings, - sysSettings:SystemSettings, - repSettings:ReportSettings, - filterSettings:FilterSettings) -> None: + def __init__(self, + operator_settings: OperatorSettings, + system_settings: SystemSettings, + report_settings: ReportSettings, + filter_settings: FilterSettings) -> None: super().__init__() - self._operSettings = operSettings - self._sysSettings = sysSettings - self._repSettings = repSettings - self._filterSettings = filterSettings + self._operator_settings = operator_settings + self._system_settings = system_settings + self._report_settings = report_settings + self._filter_settings = filter_settings self._build_dock_widgets() self._build_menu() - + def get_widget(self) -> QWidget: + """ + Возвращает виджет меню. + """ return self - - def setup(self, parent:QMainWindow) -> None: + + def setup(self, parent: QMainWindow) -> None: + """ + Добавляет док-виджеты и устанавливает главное меню для главного окна. + + :param parent: Главное окно приложения. + """ parent.addDockWidget(Qt.RightDockWidgetArea, self._operator_dock) parent.addDockWidget(Qt.RightDockWidgetArea, self._system_dock) parent.addDockWidget(Qt.RightDockWidgetArea, self._report_dock) parent.addDockWidget(Qt.RightDockWidgetArea, self._filter_dock) parent.setMenuBar(self) - + def _build_dock_widgets(self) -> None: """ - Инициализация док-виджетов для настроек. + Инициализирует док-виджеты для настроек и скрывает их по умолчанию. """ - # Создаем док-виджет для OperatorSettings + # Док-виджет для настроек оператора self._operator_dock = QDockWidget("Operator Settings", self) - self._operator_dock.setWidget(self._operSettings) + self._operator_dock.setWidget(self._operator_settings) self._operator_dock.setObjectName("OperatorSettings") - self._operator_dock.hide() # Скрываем по умолчанию + self._operator_dock.hide() - # Создаем док-виджет для SystemSettings + # Док-виджет для системных настроек self._system_dock = QDockWidget("System Settings", self) - self._system_dock.setWidget(self._sysSettings) + self._system_dock.setWidget(self._system_settings) self._system_dock.setObjectName("SystemSettings") - self._system_dock.hide() # Скрываем по умолчанию + self._system_dock.hide() - # Создаем док-виджет для ReportSettings + # Док-виджет для настроек представления отчёта self._report_dock = QDockWidget("View settings", self) - self._report_dock.setWidget(self._repSettings) + self._report_dock.setWidget(self._report_settings) self._report_dock.setObjectName("ReportSettings") - self._report_dock.hide() # Скрываем по умолчанию + self._report_dock.hide() - # Создаем док-виджет для filterSettings + # Док-виджет для фильтр-настроек self._filter_dock = QDockWidget("Filter settings", self) - self._filter_dock.setWidget(self._filterSettings) + self._filter_dock.setWidget(self._filter_settings) self._filter_dock.setObjectName("FilterSetting") - self._filter_dock.hide() # Скрываем по умолчанию + self._filter_dock.hide() - # Настройка док-виджетов + # Устанавливаем функциональные возможности для каждого док-виджета self._set_dock_features(self._operator_dock) self._set_dock_features(self._system_dock) self._set_dock_features(self._report_dock) @@ -205,144 +284,176 @@ class CustomMenuBar(QMenuBar): def _build_menu(self) -> None: """ - Инициализация главного меню. + Инициализирует элементы главного меню. """ - # Создаем меню "Режимы" + # Создаем меню для выбора режима и настроек modes_menu = self.addMenu("Mode") settings_menu = self.addMenu("Settings") - # Создаем действия для меню - self.seeking_action = QAction("Real time folder scanning", self) - self.raport_action = QAction("Raport editor", self) - self.client_action = QAction("Client trace processor", self) + # Действия для переключения режимов + self.action_scanning = QAction("Real time folder scanning", self) + self.action_report = QAction("Raport editor", self) + self.action_client = QAction("Client trace processor", self) - system_settings = QAction("System settings", self) - system_settings.setIcon(QIcon('resources/system_ico.png')) - system_settings.triggered.connect(lambda: self._toggle_visibility(self._system_dock)) + # Действия для настроек + system_settings_action = QAction("System settings", self) + system_settings_action.setIcon(QIcon('resources/system_ico.png')) + system_settings_action.triggered.connect(lambda: self._toggle_visibility(self._system_dock)) - operator_settings = QAction("Operator settings ", self) - operator_settings.setIcon(QIcon('resources/operator_ico.png')) - operator_settings.triggered.connect(lambda: self._toggle_visibility(self._operator_dock)) + operator_settings_action = QAction("Operator settings", self) + operator_settings_action.setIcon(QIcon('resources/operator_ico.png')) + operator_settings_action.triggered.connect(lambda: self._toggle_visibility(self._operator_dock)) - self.view_settings = QAction("View settings", self) - self.view_settings.setIcon(QIcon('resources/view_ico.png')) - self.view_settings.triggered.connect(lambda: self._toggle_visibility(self._report_dock)) + self.action_view_settings = QAction("View settings", self) + self.action_view_settings.setIcon(QIcon('resources/view_ico.png')) + self.action_view_settings.triggered.connect(lambda: self._toggle_visibility(self._report_dock)) - self.filter_settings = QAction("Filter settings", self) - #self.filter_settings.setIcon(QIcon('resources/view_ico.png')) - self.filter_settings.triggered.connect(lambda: self._toggle_visibility(self._filter_dock)) + self.action_filter_settings = QAction("Filter settings", self) + self.action_filter_settings.triggered.connect(lambda: self._toggle_visibility(self._filter_dock)) - # Добавляем действия в меню "Режимы" - modes_menu.addAction(self.seeking_action) - modes_menu.addAction(self.raport_action) - modes_menu.addAction(self.client_action) + # Добавляем действия в меню "Mode" + modes_menu.addAction(self.action_scanning) + modes_menu.addAction(self.action_report) + modes_menu.addAction(self.action_client) - settings_menu.addAction(system_settings) - settings_menu.addAction(operator_settings) - settings_menu.addAction(self.view_settings) - settings_menu.addAction(self.filter_settings) + # Добавляем действия в меню "Settings" + settings_menu.addAction(system_settings_action) + settings_menu.addAction(operator_settings_action) + settings_menu.addAction(self.action_view_settings) + settings_menu.addAction(self.action_filter_settings) - def _toggle_visibility(self, body:QDockWidget = None) -> None: + def _toggle_visibility(self, dock: QDockWidget = None) -> None: """ - Переключение видимости док-виджета. + Переключает видимость указанного док-виджета. + + :param dock: Док-виджет для переключения. """ - if body: - is_visible = body.isVisible() - body.setVisible(not is_visible) + if dock: + is_visible = dock.isVisible() + dock.setVisible(not is_visible) @staticmethod - def _set_dock_features(body:QDockWidget = None) -> None: + def _set_dock_features(dock: QDockWidget = None) -> None: """ - Настройка флагов док-виджета. + Устанавливает возможность перемещения, закрытия и открепления для док-виджета. + + :param dock: Док-виджет для настройки. """ - if body: - flag_move = QDockWidget.DockWidgetMovable - flag_close = QDockWidget.DockWidgetClosable - flag_floating = QDockWidget.DockWidgetFloatable - body.setFeatures(flag_move | flag_close | flag_floating) + if dock: + features = QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable + dock.setFeatures(features) class RaportWidget(QWidget): + """ + Виджет для режима редактирования отчёта. - def __init__(self, tabWidget:CustomTabWidget): + Содержит вкладки и кнопки для сохранения состояния и открытия файла. + """ + + def __init__(self, tab_widget: CustomTabWidget): super().__init__() - self._tabWidget = tabWidget + self._tab_widget = tab_widget self._build_widget() def get_widget(self) -> QWidget: + """ + Возвращает виджет. + """ return self - def _build_widget(self): - main_layout = QVBoxLayout() - self.save_screen_btn = QPushButton("Save state") - self.save_screen_btn.setFixedWidth(185) - self.open_file_btn = QPushButton("Open file") - self.open_file_btn.setFixedWidth(185) + def _build_widget(self) -> None: + """ + Строит макет виджета с вкладками и кнопками управления. + """ + main_layout = QVBoxLayout() + self.btn_save_state = QPushButton("Save state") + self.btn_save_state.setFixedWidth(185) + self.btn_open_file = QPushButton("Open file") + self.btn_open_file.setFixedWidth(185) button_layout = QHBoxLayout() button_layout.setSpacing(2) + button_layout.addWidget(self.btn_save_state) + button_layout.addWidget(self.btn_open_file) + button_container = QWidget() + button_container.setLayout(button_layout) - button_layout.addWidget(self.save_screen_btn) - button_layout.addWidget(self.open_file_btn) - button_widget = QWidget() - button_widget.setLayout(button_layout) - - main_layout.addWidget(self._tabWidget) - main_layout.addWidget(button_widget) + main_layout.addWidget(self._tab_widget) + main_layout.addWidget(button_container) self.setLayout(main_layout) class SeekingWidget(QWidget): + """ + Виджет для режима поиска (сканирования папок). - def __init__(self, tabWidget:CustomTabWidget): + """ + + def __init__(self, tab_widget: CustomTabWidget): super().__init__() - self._tabWidget = tabWidget + self._tab_widget = tab_widget self._build_widget() - + def get_widget(self) -> QWidget: + """ + Возвращает виджет. + """ return self - def _build_widget(self): - main_layout = QVBoxLayout() + def _build_widget(self) -> None: + """ + Создает макет виджета с вкладками. + """ + main_layout = QVBoxLayout() button_layout = QHBoxLayout() button_layout.setSpacing(2) - button_widget = QWidget() - button_widget.setLayout(button_layout) - - main_layout.addWidget(self._tabWidget) - main_layout.addWidget(button_widget) + button_container = QWidget() + button_container.setLayout(button_layout) + + main_layout.addWidget(self._tab_widget) + main_layout.addWidget(button_container) self.setLayout(main_layout) - + class ClientAnalyzerWidget(QWidget): + """ + Виджет для клиентского анализа трассировки. - def __init__(self, tabWidget:CustomTabWidget): + Содержит вкладки и кнопки для сохранения состояния, открытия папки и расчёта TCW. + """ + + def __init__(self, tab_widget: CustomTabWidget): super().__init__() - self._tabWidget = tabWidget + self._tab_widget = tab_widget self._build_widget() def get_widget(self) -> QWidget: + """ + Возвращает виджет. + """ return self - def _build_widget(self): - main_layout = QVBoxLayout() - self.save_screen_btn = QPushButton("Save state") - self.save_screen_btn.setFixedWidth(185) - self.open_folder_btn = QPushButton("Open folder") - self.open_folder_btn.setFixedWidth(185) - self.build_TCW_btn = QPushButton("Calculate TCW") - self.build_TCW_btn.setFixedWidth(185) + def _build_widget(self) -> None: + """ + Строит макет виджета с вкладками и управляющими кнопками. + """ + main_layout = QVBoxLayout() + self.btn_save_state = QPushButton("Save state") + self.btn_save_state.setFixedWidth(185) + self.btn_open_folder = QPushButton("Open folder") + self.btn_open_folder.setFixedWidth(185) + self.btn_calc_tcw = QPushButton("Calculate TCW") + self.btn_calc_tcw.setFixedWidth(185) button_layout = QHBoxLayout() button_layout.setSpacing(2) + button_layout.addWidget(self.btn_save_state) + button_layout.addWidget(self.btn_open_folder) + button_layout.addWidget(self.btn_calc_tcw) + button_container = QWidget() + button_container.setLayout(button_layout) - button_layout.addWidget(self.save_screen_btn) - button_layout.addWidget(self.open_folder_btn) - button_layout.addWidget(self.build_TCW_btn) - button_widget = QWidget() - button_widget.setLayout(button_layout) - - main_layout.addWidget(self._tabWidget) - main_layout.addWidget(button_widget) - self.setLayout(main_layout) - \ No newline at end of file + main_layout.addWidget(self._tab_widget) + main_layout.addWidget(button_container) + self.setLayout(main_layout)