chore: переработан main_widget + связь с контроллером перенесена на сигналы

This commit is contained in:
Andrew 2025-01-22 18:23:50 +03:00
parent 2ca5034c45
commit 67d237e4ed
7 changed files with 480 additions and 381 deletions

View File

@ -367,6 +367,7 @@ class BaseController(QObject):
def __init__(self,
mediator: Optional[BaseMediator] = None,
file_manager: Optional[BaseFileManager] = None):
super().__init__()
self._mediator = mediator
self._file_manager = file_manager

View File

@ -1,37 +1,44 @@
from typing import Union
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QWidget, QTabWidget
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import pyqtSignal
from base.base import BaseController
class Controller(BaseController):
signal_widgets = pyqtSignal(list)
signal_progress_bar = pyqtSignal(int)
signal_status_text = pyqtSignal(str)
def update_settings(self, settings: list[dict]) -> None:
self.mediator.notify(settings)
# TODO: Объедини переключение режимов в один метод, и по входному аргументу (например 1 и 2) переключай их.
def set_working_mode(self, mode:int) -> None:
self._file_manager.set_mode(mode)
def open_file(self, filepath: str) -> None:
self._file_manager.open_custom_file(filepath)
def update_plots(self) -> None:
self._file_manager.replot_all()
def send_widgets(self, widgets: list[QWidget]) -> None:
self.signal_widgets.emit(widgets)
def update_settings(self, settings: list[dict]) -> None:
self.mediator.notify(self, settings)
def update_status(self, msg:str) -> None:
self.signal_status_text.emit(msg)
def update_progress(self, progress:int) -> None:
self.signal_progress_bar.emit(progress)
def open_file(self, filepath: str) -> None:
self._file_manager.open_custom_file(filepath)
def save_file(self, data:list[str, QTabWidget]) -> None:
filepath, tab = data
pixmap = QPixmap(tab.size())
tab.render(pixmap)
pixmap.save(filepath)

View File

@ -1,361 +0,0 @@
from datetime import datetime as dt
from typing import Optional
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QSizePolicy as QSP
from base.base import BaseMainWindow, BaseController
from gui.settings_window import SystemSettings, OperatorSettings
from gui.reportGui import ReportSettings
# FIXME: При отркытии RaportMode все прочитанные трейсы должны удаляться, но они открываются...
class MainWindow(BaseMainWindow):
def __init__(self,
controller: Optional[BaseController] = None) -> None:
# TODO: Почему контроллер Optional? Нигде нет обработки случаев, если он будет None: при вызове его методов
# будет ошибка.
# TODO: Касательно передачи экземпляра контроллера в конструктор. Не лучше ли реализовать взаимодействие с ним
# через сигналы? Как минимум это позволит исключить странную зависимость интерфейса от контроллера.
# Логичнее было бы использовать данный класс в качестве фасада над виджетами, о чем сказано ниже.
super().__init__()
self._controller = controller
# TODO: касательно ВСЕХ методов данного класса, СОЗДАЮЩИХ ВИДЖЕТЫ. Исходя из названия данного класса - это
# финальное главное окно приложения: оно не должно создавать виджеты, а уже использовать готовые, поэтому
# правильнее будет каждый создаваемый тут виджет вынести в отдельный модуль в отдельный класс, там выполнять
# его создание и настройку, а тут уже получать готовый экземпляр виджета и его отображать.
self._init_startUI()
self._init_dock_widgets()
self._init_menu()
def _init_TabWidget(self) -> None:
self.tabWidget = QtWidgets.QTabWidget()
self.tabWidget.setTabsClosable(True)
self.tabWidget.tabCloseRequested.connect(self._close_tab)
self.tabWidget.currentChanged.connect(self._on_tab_changed)
def _init_startUI(self) -> None:
self.operSettings = OperatorSettings("params/operator_params.json", 'Operator', self._upd_settings)
self.sysSettings = SystemSettings("params/system_params.json", 'System', self._upd_settings)
self.repSettings = ReportSettings()
self._clear()
self.resize(800,800)
seeking_mode_btn = QtWidgets.QPushButton("Real time folder scanning")
seeking_mode_btn.setFixedWidth(300)
seeking_mode_btn.clicked.connect(self._init_seekingUI)
raport_mode_btn = QtWidgets.QPushButton("Raport editor")
raport_mode_btn.setFixedWidth(300)
raport_mode_btn.clicked.connect(self._init_raportUI)
button_layout = QtWidgets.QHBoxLayout()
button_layout.setSpacing(2)
button_layout.addWidget(seeking_mode_btn)
button_layout.addWidget(raport_mode_btn)
button_widget = QtWidgets.QWidget()
button_widget.setLayout(button_layout)
mainLayout = self._central_layout
label = QtWidgets.QLabel("Select work mode")
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._init_statusBar()
def _init_dock_widgets(self) -> None:
"""
Инициализация док-виджетов для настроек.
"""
# Создаем док-виджет для OperatorSettings
self.operator_dock = QtWidgets.QDockWidget("Operator Settings", self)
self.operator_dock.setWidget(self.operSettings)
self.operator_dock.setObjectName("OperatorSettings")
self.addDockWidget(Qt.RightDockWidgetArea, self.operator_dock)
self.operator_dock.hide() # Скрываем по умолчанию
# Создаем док-виджет для SystemSettings
self.system_dock = QtWidgets.QDockWidget("System Settings", self)
self.system_dock.setWidget(self.sysSettings)
self.system_dock.setObjectName("SystemSettings")
self.addDockWidget(Qt.RightDockWidgetArea, self.system_dock)
self.system_dock.hide() # Скрываем по умолчанию
# Создаем док-виджет для ReportSettings
self.report_dock = QtWidgets.QDockWidget("View settings", self)
self.report_dock.setWidget(self.repSettings)
self.report_dock.setObjectName("ReportSettings")
self.addDockWidget(Qt.RightDockWidgetArea, self.report_dock)
self.report_dock.hide() # Скрываем по умолчанию
# Настройка док-виджетов
self._set_dock_features(self.operator_dock)
self._set_dock_features(self.system_dock)
self._set_dock_features(self.report_dock)
def _init_menu(self) -> None:
"""
Инициализация главного меню.
"""
# Создаем главное меню
menu_bar = self.menuBar()
# Создаем меню "Режимы"
modes_menu = menu_bar.addMenu("Mode")
settings_menu = menu_bar.addMenu("Settings")
# Создаем действия для меню
seeking_action = QtWidgets.QAction("Real time folder scanning", self)
seeking_action.triggered.connect(self._init_seekingUI)
raport_action = QtWidgets.QAction("Raport editor", self)
raport_action.triggered.connect(self._init_raportUI)
system_settings = QtWidgets.QAction("System settings", self)
system_settings.setIcon(QIcon('resources/system_ico.png'))
system_settings.triggered.connect(lambda: self._toggle_visibility(self.system_dock))
operator_settings = QtWidgets.QAction("Operator settings ", self)
operator_settings.setIcon(QIcon('resources/operator_ico.png'))
operator_settings.triggered.connect(lambda: self._toggle_visibility(self.operator_dock))
view_settings = QtWidgets.QAction("View settings", self)
view_settings.setIcon(QIcon('resources/view_ico.png'))
view_settings.triggered.connect(lambda: self._toggle_visibility(self.report_dock))
view_settings.triggered.connect(lambda: self._on_tab_changed(0))
# Добавляем действия в меню "Режимы"
modes_menu.addAction(seeking_action)
modes_menu.addAction(raport_action)
settings_menu.addAction(system_settings)
settings_menu.addAction(operator_settings)
settings_menu.addAction(view_settings)
def _init_statusBar(self) -> None:
# Создание пользовательского виджета для StatusBar
note_widget = QtWidgets.QWidget()
note_layout = QtWidgets.QHBoxLayout(note_widget)
note_layout.setContentsMargins(10, 1, 10, 1)
note_layout.setSpacing(15) # Устанавливаем расстояние между элементами
# Создание QLabel и QProgressBar
self.mode_label = QtWidgets.QLabel()
self.note_label = QtWidgets.QLabel()
self.progress_bar = QtWidgets.QProgressBar()
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(0)
self.progress_bar.setMinimumWidth(250)
self.progress_bar.setMaximumHeight(10)
self.progress_bar.setTextVisible(False)
# Создание QSpacerItem
# Установка политики размеров
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)
# Установка политики размеров для note_widget
note_widget.setSizePolicy(QSP.Policy.Expanding, QSP.Policy.Preferred)
# Добавление пользовательского виджета в StatusBar как Permanent Widget
self.statusBar().addPermanentWidget(note_widget, 1)
def _toggle_visibility(self, body:QtWidgets.QDockWidget = None) -> None:
"""
Переключение видимости док-виджета.
"""
is_visible = body.isVisible()
body.setVisible(not is_visible)
def _set_dock_features(self, body:QtWidgets.QDockWidget = None) -> None:
"""
Настройка флагов док-виджета.
"""
flag_move = QtWidgets.QDockWidget.DockWidgetMovable
flag_close = QtWidgets.QDockWidget.DockWidgetClosable
flag_floating = QtWidgets.QDockWidget.DockWidgetFloatable
body.setFeatures(flag_move | flag_close | flag_floating)
def _clear(self) -> None:
if self._central_layout is not None:
while self._central_layout.count():
child = self._central_layout.takeAt(0)
if child.widget() is not None:
child.widget().deleteLater()
# TODO: По методам self._init_seekingUI и self._init_raportUI:
# 1. Дублирование кода (блок из первых трех строк) - вынести в отдельный метод
# 2. Оба метода призваны проинициализировать UI, но в то же время занимаются созданием виджетов и еще что-то
# в контроллере дергают: создание виджетов вынести отдельно, контроллеру сообщить о чем-то при помощи
# pyqtSignal при нажатии кнопки или выборе пункта меню.
def _init_seekingUI(self) -> None:
self._clear()
self._init_TabWidget()
self._transfer_settings()
button_layout = QtWidgets.QHBoxLayout()
button_layout.setSpacing(2)
button_widget = QtWidgets.QWidget()
button_widget.setLayout(button_layout)
self.mode_label.setText("online mode")
self._central_layout.addWidget(self.tabWidget)
self._central_layout.addWidget(button_widget)
self._controller.seeking_mode()
def _init_raportUI(self) -> None:
self._clear()
self._init_TabWidget()
self._transfer_settings()
save_screen_btn = QtWidgets.QPushButton("Save state")
save_screen_btn.setFixedWidth(185)
save_screen_btn.clicked.connect(self._save_plots)
open_file_btn = QtWidgets.QPushButton("Open file")
open_file_btn.setFixedWidth(185)
open_file_btn.clicked.connect(self._open_file)
button_layout = QtWidgets.QHBoxLayout()
button_layout.setSpacing(2)
button_layout.addWidget(save_screen_btn)
button_layout.addWidget(open_file_btn)
button_widget = QtWidgets.QWidget()
button_widget.setLayout(button_layout)
self.mode_label.setText("raport mode")
self._central_layout.addWidget(self.tabWidget)
self._central_layout.addWidget(button_widget)
self._controller.raport_mode()
def show_plot_tabs(self, plot_widgets: list[QtWidgets.QWidget]) -> None:
for plot_widget in plot_widgets:
widget, reg_items, curve_items, qt_items = plot_widget
tab = QtWidgets.QWidget()
tab.setProperty("reg_items", reg_items)
tab.setProperty("curve_items", curve_items)
tab.setProperty("qt_items", qt_items)
grid = QtWidgets.QGridLayout()
grid.addWidget(widget)
tab.setLayout(grid)
self.tabWidget.addTab(tab, "SF_trace_" + dt.now().strftime('%Y_%m_%d-%H_%M_%S'))
self.tabWidget.setCurrentWidget(tab)
tab_count = self.tabWidget.count()
if tab_count > 10:
for i in range(0, tab_count-10):
self._close_tab(i)
self.update_stateLabel("Done!")
def keyPressEvent(self, a0) -> None:
if a0.key() == Qt.Key_F5:
tab_count = self.tabWidget.count()
for i in range(0, tab_count):
self._close_tab(i)
def closeEvent(self, a0):
self.operSettings.close()
self.sysSettings.close()
self.repSettings.close()
super().closeEvent(a0)
def update_progressBar(self, percent:int) -> None:
if percent > 100: percent = 100
self.progress_bar.setValue(percent)
def update_stateLabel(self, msg: str = None) -> None:
self.note_label.setText(msg)
self.note_label.adjustSize()
def _transfer_settings(self) -> None:
operator_params = self.operSettings.getParams()
system_params = self.sysSettings.getParams()
self._controller.update_settings([operator_params, system_params])
def _upd_settings(self) -> None:
self._transfer_settings()
if self.mode_label.text():
self.tabWidget.clear()
self._controller.update_plots()
def _close_tab(self, index:int) -> None:
self.tabWidget.removeTab(index)
# TODO: Зачем разделять эти 2 метода? В self._select_csv путь к файлу получили и контроллеру сигналом отправили.
def _open_file(self) -> None:
path = self._select_csv()
if path is not None:
self._controller.open_file(path)
def _select_csv(self) -> Optional[str]:
CSV_path, _ = QtWidgets.QFileDialog.getOpenFileName(self,"Select csv file", "", "CSV Files (*.csv)")
if CSV_path:
print(CSV_path)
return CSV_path
return None
def _on_tab_changed(self, index):
try:
tab = self.tabWidget.currentWidget()
except:
# TODO: Очень плохая практика - не указывать конкретный тип исключений.
tab = None
if tab is not None and self.report_dock.isVisible():
reg_items = tab.property("reg_items")
curve_items = tab.property("curve_items")
qt_items = tab.property("qt_items")
self.repSettings.build(index, reg_items, curve_items, qt_items)
def _save_plots(self) -> None:
# TODO: Нарушение принципа единичной ответственности. Почему ИНТЕРФЕЙС занимается сохранением чего-то?
# От него должен только исходить призыв к действию (кнопка или что-то подобное), сама логика же должна
# быть в другом месте.
# TODO: эта реализация работает, но для пользователя будет больно каждый раз писать имена и расширения
# сохраняемых файлов, не кажется? Можно сделать, как показано ниже, тогда файлам будет назначаться имя
# по умолчанию и с расширением. ХЗ правда, как эта форма на винде будет выглядеть - надо проверить.
# ========================================================
# dialog = QFileDialog()
# dialog.setOptions(QFileDialog.DontUseNativeDialog)
# dialog.setFileMode(QFileDialog.AnyFile)
# dialog.setAcceptMode(QFileDialog.AcceptSave)
# dialog.setDirectory(os.getcwd())
# dialog.selectFile("untitled.txt")
# dialog.exec_()
# if dialog.accepted:
# # emit signal to save file
# ...
# ========================================================
filepath, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save file", "", "Image Files (*.png *.jpeg)")
tab = self.tabWidget.currentWidget()
if tab is not None:
pixmap = QPixmap(tab.size())
tab.render(pixmap)
pixmap.save(filepath)

155
src/gui/main_gui.py Normal file
View File

@ -0,0 +1,155 @@
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt, pyqtSignal
from base.base import BaseMainWindow
from gui.start_widget import (CustomMenuBar, CustomStatusBar,
StartWidget, CustomTabWidget,
RaportWidget, SeekingWidget)
from gui.settings_window import SystemSettings, OperatorSettings
from gui.report_gui import ReportSettings
# FIXME: При отркытии RaportMode все прочитанные трейсы должны удаляться, но они открываются...
class MainWindow(BaseMainWindow):
signal_mode = pyqtSignal(int)
signal_settings = pyqtSignal(list)
signal_replot_all = pyqtSignal()
signal_open_file = pyqtSignal(str)
signal_save_file = pyqtSignal(list)
def __init__(self) -> None:
super().__init__()
self._init_startUI()
def _init_startUI(self) -> None:
self._init_settings()
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)
self.setCentralWidget(start_widget.get_widget())
def _init_settings(self) -> None:
self.sysSettings = SystemSettings("params/system_params.json", 'System', self._upd_settings)
self.repSettings = ReportSettings()
self.operSettings = OperatorSettings("params/operator_params.json", 'Operator', self._upd_settings)
def _init_menu(self) -> None:
self.menu = CustomMenuBar(self.sysSettings, self.repSettings, self.operSettings)
self.menu.seeking_action.triggered.connect(self._init_seekingUI)
self.menu.raport_action.triggered.connect(self._init_raportUI)
self.menu.view_settings.triggered.connect(lambda: self._on_tab_changed(0))
self.menu.setup(self)
def _init_status_bar(self) -> None:
self.status_widget = CustomStatusBar()
self.statusBar().addPermanentWidget(self.status_widget.get_widget(), 1)
def _init_tab_widget(self) -> None:
self._tab_widget = CustomTabWidget()
self._tab_widget.currentChanged.connect(self._on_tab_changed)
def _on_tab_changed(self, index):
tab = self._tab_widget.currentWidget()
if tab:
reg_items = tab.property("reg_items")
curve_items = tab.property("curve_items")
qt_items = tab.property("qt_items")
self.repSettings.build(index, reg_items, curve_items, qt_items)
def _clear(self) -> None:
if self.layout() is not None:
while self.layout().count():
child = self.layout().takeAt(0)
if child.widget() is not None:
child.widget().deleteLater()
self._init_tab_widget()
self._transfer_settings()
def _init_raportUI(self) -> None:
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)
self.setCentralWidget(raport_widget.get_widget())
def _init_seekingUI(self) -> None:
self._clear()
self._set_mode(2)
seeking_widget = SeekingWidget(self._tab_widget)
self.setCentralWidget(seeking_widget.get_widget())
def _set_mode(self, num:int) -> None:
match num:
case 1:
self.status_widget.set_mode("raport mode")
self.signal_mode.emit(1)
case 2:
self.status_widget.set_mode("online mode")
self.signal_mode.emit(2)
def show_plot_tabs(self, plot_widgets: list[QtWidgets.QWidget]) -> None:
for plot_widget in plot_widgets:
self._tab_widget.create_tab(plot_widget)
tab_count = self._tab_widget.count()
if tab_count > 10:
for i in range(0, tab_count-10):
self._tab_widget.close_tab(i)
self.status_widget.set_note("Done!")
self.status_widget.set_progress(100)
def keyPressEvent(self, a0) -> None:
if a0.key() == Qt.Key_F5:
tab_count = self._tab_widget.count()
for i in range(0, tab_count):
self._tab_widget.close_tab(i)
def closeEvent(self, a0):
self.operSettings.close()
self.sysSettings.close()
self.repSettings.close()
super().closeEvent(a0)
def _transfer_settings(self) -> None:
operator_params = self.operSettings.getParams()
system_params = self.sysSettings.getParams()
self.signal_settings.emit([operator_params, system_params])
def _upd_settings(self) -> None:
self._transfer_settings()
if self.status_widget._mode_label.text():
self._tab_widget.clear()
self.signal_replot_all.emit()
def _open_file(self) -> None:
CSV_path, _ = QtWidgets.QFileDialog.getOpenFileName(self,"Select csv file", "", "CSV Files (*.csv)")
if CSV_path:
self.signal_open_file.emit(CSV_path)
def _save_plots(self) -> None:
filepath, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save file", "", "Image Files (*.png *.jpeg)")
tab = self._tab_widget.currentWidget()
if tab: self.signal_save_file.emit([filepath, tab])
# TODO: эта реализация работает, но для пользователя будет больно каждый раз писать имена и расширения
# сохраняемых файлов, не кажется? Можно сделать, как показано ниже, тогда файлам будет назначаться имя
# по умолчанию и с расширением. ХЗ правда, как эта форма на винде будет выглядеть - надо проверить.
# ========================================================
# dialog = QFileDialog()
# dialog.setOptions(QFileDialog.DontUseNativeDialog)
# dialog.setFileMode(QFileDialog.AnyFile)
# dialog.setAcceptMode(QFileDialog.AcceptSave)
# dialog.setDirectory(os.getcwd())
# dialog.selectFile("untitled.txt")
# dialog.exec_()
# if dialog.accepted:
# # emit signal to save file
# ...
# ========================================================

295
src/gui/start_widget.py Normal file
View File

@ -0,0 +1,295 @@
from datetime import datetime as dt
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
from gui.settings_window import SystemSettings, OperatorSettings
from gui.report_gui import ReportSettings
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(300)
self.raport_mode_btn = QPushButton("Raport editor")
self.raport_mode_btn.setFixedWidth(300)
button_layout = QHBoxLayout()
button_layout.setSpacing(2)
button_layout.addWidget(self.seeking_mode_btn)
button_layout.addWidget(self.raport_mode_btn)
button_widget = QWidget()
button_widget.setLayout(button_layout)
mainLayout = QVBoxLayout()
label = QLabel("Select work mode")
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)
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)
self._mode_label.setText(msg)
self._mode_label.adjustSize()
def set_note(self, msg:str = '') -> None:
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
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
self._mode_label = QLabel()
self._note_label = QLabel()
self._progress_bar = QProgressBar()
self._progress_bar.setRange(0, 100)
self._progress_bar.setValue(0)
self._progress_bar.setMinimumWidth(250)
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)
self.setSizePolicy(QSP.Policy.Expanding, QSP.Policy.Preferred)
class CustomTabWidget(QTabWidget):
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:
widget, reg_items, curve_items, qt_items = plot_widget
tab = QWidget()
tab.setProperty("reg_items", reg_items)
tab.setProperty("curve_items", curve_items)
tab.setProperty("qt_items", qt_items)
grid = QGridLayout()
grid.addWidget(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:
if self.count() > index and index >= 0:
self.removeTab(index)
class CustomMenuBar(QMenuBar):
def __init__(self,
operSettings:OperatorSettings,
sysSettings:SystemSettings,
repSettings:ReportSettings) -> None:
super().__init__()
self._operSettings = operSettings
self._sysSettings = sysSettings
self._repSettings = repSettings
self._build_dock_widgets()
self._build_menu()
def get_widget(self) -> QWidget:
return self
def setup(self, parent:QMainWindow) -> None:
parent.addDockWidget(Qt.RightDockWidgetArea, self._operator_dock)
parent.addDockWidget(Qt.RightDockWidgetArea, self._system_dock)
parent.addDockWidget(Qt.RightDockWidgetArea, self._report_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.setObjectName("OperatorSettings")
self._operator_dock.hide() # Скрываем по умолчанию
# Создаем док-виджет для SystemSettings
self._system_dock = QDockWidget("System Settings", self)
self._system_dock.setWidget(self._sysSettings)
self._system_dock.setObjectName("SystemSettings")
self._system_dock.hide() # Скрываем по умолчанию
# Создаем док-виджет для ReportSettings
self._report_dock = QDockWidget("View settings", self)
self._report_dock.setWidget(self._repSettings)
self._report_dock.setObjectName("ReportSettings")
self._report_dock.hide() # Скрываем по умолчанию
# Настройка док-виджетов
self._set_dock_features(self._operator_dock)
self._set_dock_features(self._system_dock)
self._set_dock_features(self._report_dock)
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)
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))
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))
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))
# Добавляем действия в меню "Режимы"
modes_menu.addAction(self.seeking_action)
modes_menu.addAction(self.raport_action)
settings_menu.addAction(system_settings)
settings_menu.addAction(operator_settings)
settings_menu.addAction(self.view_settings)
def _toggle_visibility(self, body:QDockWidget = None) -> None:
"""
Переключение видимости док-виджета.
"""
if body:
is_visible = body.isVisible()
body.setVisible(not is_visible)
@staticmethod
def _set_dock_features(body:QDockWidget = None) -> None:
"""
Настройка флагов док-виджета.
"""
if body:
flag_move = QDockWidget.DockWidgetMovable
flag_close = QDockWidget.DockWidgetClosable
flag_floating = QDockWidget.DockWidgetFloatable
body.setFeatures(flag_move | flag_close | flag_floating)
class RaportWidget(QWidget):
def __init__(self, tabWidget:CustomTabWidget):
super().__init__()
self._tabWidget = tabWidget
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)
button_layout = QHBoxLayout()
button_layout.setSpacing(2)
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)
self.setLayout(main_layout)
class SeekingWidget(QWidget):
def __init__(self, tabWidget:CustomTabWidget):
super().__init__()
self._tabWidget = tabWidget
self._build_widget()
def get_widget(self) -> QWidget:
return self
def _build_widget(self):
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)
self.setLayout(main_layout)

View File

@ -3,8 +3,8 @@ import sys
import pyqtgraph as pg
from PyQt5 import QtWidgets
from gui.mainGui import MainWindow
from src.controller.file_manager import DirectoryMonitor
from gui.main_gui import MainWindow
from controller.file_manager import DirectoryMonitor, FileManager
from controller.mediator import Mediator
from controller.converter import DataConverter
from gui.plotter import PlotWidget
@ -17,22 +17,24 @@ def main():
pg.setConfigOptions(useOpenGL=False, antialias=False)
app = QtWidgets.QApplication(sys.argv)
monitor = DirectoryMonitor()
file_manager = FileManager(monitor=monitor)
data_converter = DataConverter()
plot_widget_builder = PlotWidget()
controller = Controller()
controller = Controller(file_manager=file_manager)
passport_former = PassportFormer()
window = MainWindow(controller)
mediator = Mediator(monitor, data_converter, passport_former, plot_widget_builder, controller)
window = MainWindow()
mediator = Mediator(data_converter, passport_former, plot_widget_builder, controller, file_manager)
window.show()
window.signal_mode.connect(controller.set_working_mode)
window.signal_settings.connect(controller.update_settings)
window.signal_replot_all.connect(controller.update_plots)
window.signal_open_file.connect(controller.open_file)
window.signal_save_file.connect(controller.save_file)
controller.signal_widgets.connect(window.show_plot_tabs)
controller.signal_progress_bar.connect(window.update_progressBar)
controller.signal_status_text.connect(window.update_stateLabel)
#controller.signal_settings.connect(mediator.update_settings)
#controller.signal_open_file.connect(monitor.custom_csv_extract_only)
#controller.signal_raport_mode.connect(monitor.start_raport)
#controller.signal_seeking_mode.connect(monitor.start_seeking)
#controller.signal_update_plots.connect(monitor.update_plots)
controller.signal_progress_bar.connect(window.status_widget.set_progress)
controller.signal_status_text.connect(window.status_widget.set_note)
sys.exit(app.exec_())