def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) try: self.settings = settings.get_ini_settings( os.path.join(self.get_application_path(), "settings.ini")) ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("ini_err")) if ini_ok: self.settings.restore_qwidget_state(self) self.settings.restore_qwidget_state(self.ui.mw_splitter_1) self.settings.restore_qwidget_state(self.ui.measures_table) self.ui.download_progress_bar.setHidden(True) if ENGLISH_VERSION: self.ui.russian_language_action.setVisible(False) self.settings.language = Text.Lang.EN self.translator = QtCore.QTranslator( QtWidgets.QApplication.instance()) self.install_translator(self.settings.language) if self.settings.language == Text.Lang.EN: self.ui.english_language_action.setChecked(True) else: self.ui.russian_language_action.setChecked(True) self.set_up_logger() self.ui.measures_table.setItemDelegate( TransparentPainterForView(self.ui.measures_table, "#d4d4ff")) self.ui.download_path_edit.setText(self.settings.save_folder_path) self.ui.ip_combobox.setEditText(self.settings.ip) self.ui.download_path_edit.setText(self.settings.path) self.ui.name_template_edit.setText(self.settings.name_template) self.ui.save_folder_edit.setText(self.settings.save_folder) self.db = UpmsDatabase( os.path.join(self.get_application_path(), "database.db")) self.measures_table_model = None self.proxy = None self.update_model() self.bcast_sockets = {} self.get_broadcast_ips() self.show() self.connect_all() self.ui.get_ip_button.click() else: self.close()
def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) self.active_window = None try: self.settings = Settings(self) ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical( self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, ' 'удалите файл "settings.ini" и запустите программу заново') if ini_ok: self.db_name = "measures.db" self.db_connection = MeasuresDB.create_db(self.db_name) self.show_start_window() self.show() self.clb_signal_off_timer = QtCore.QTimer() # noinspection PyTypeChecker self.clb_signal_off_timer.timeout.connect(self.close) self.SIGNAL_OFF_TIME_MS = 200 self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path) self.usb_driver = clb_dll.UsbDrv(self.clb_driver) self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED self.calibrator = clb_dll.ClbDrv(self.clb_driver) self.clb_state = clb.State.DISCONNECTED self.usb_check_timer = QtCore.QTimer(self) self.usb_check_timer.timeout.connect(self.usb_tick) self.usb_check_timer.start(10) self.fast_config = None self.ui.enter_settings_action.triggered.connect(self.open_settings) else: self.close()
def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) try: self.settings = settings.get_clb_autocalibration_settings() ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical( self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, ' 'удалите файл "settings.ini" и запустите программу заново') if ini_ok: self.settings.restore_qwidget_state(self) self.settings.restore_qwidget_state(self.ui.mainwindow_splitter) self.settings.restore_qwidget_state(self.ui.mainwindow_splitter_2) self.settings.restore_qwidget_state(self.ui.measures_table) self.ui.measures_table.setItemDelegate( TransparentPainterForWidget(self.ui.measures_table, "#d4d4ff")) self.ui.progress_bar_widget.setHidden(True) for i in range(CellData.GetDataType.COUNT): self.ui.displayed_data_type_combobox.addItem( MainWindow.displayed_data_to_text[i]) self.set_up_logger() self.ftdi_control = FtdiControl() self.clb_driver = clb_dll.clb_dll modbus_registers_count = 700 self.usb_driver = clb_dll.UsbDrv(self.clb_driver, modbus_registers_count * 2) self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED self.calibrator = clb_dll.ClbDrv(self.clb_driver) self.clb_state = clb.State.DISCONNECTED self.netvars = NetworkVariables(f"./{clb.CLB_CONFIG_NAME}", self.calibrator, a_variables_read_delay=0) self.clb_signal_off_timer = QtCore.QTimer() # noinspection PyTypeChecker self.clb_signal_off_timer.timeout.connect(self.close) self.SIGNAL_OFF_TIME_MS = 200 self.ignore_save = False self.current_configuration_path = "" self.measure_progress_bar_value = 0 self.tstlan_dialog = None self.graphs_dialog = None self.open_correction_tables = False self.show() self.measure_manager = MeasureManager(self.ui.measures_table, self.ui.measure_data_view, self.settings, self) self.open_configuration_by_name( self.settings.last_configuration_path) self.measure_conductor = MeasureConductor(self.calibrator, self.netvars, self.measure_manager, self.settings) self.measure_conductor.all_measures_done.connect(self.measure_done) self.measure_conductor.single_measure_started.connect( self.single_measure_started) self.measure_conductor.single_measure_done.connect( self.single_measure_done) self.measure_conductor.verify_flash_done.connect( self.verify_flash_done) self.connect_all() self.tick_timer = QtCore.QTimer(self) self.tick_timer.timeout.connect(self.tick) self.tick_timer.start(10) else: self.close()
class MainWindow(QtWidgets.QMainWindow): clb_list_changed = QtCore.pyqtSignal([list]) usb_status_changed = QtCore.pyqtSignal(clb.State) signal_enable_changed = QtCore.pyqtSignal(bool) class CloseConfigOptions(IntEnum): SAVE = 0 DONT_SAVE = 1 CANCEL = 2 displayed_data_to_text = { CellData.GetDataType.MEASURED: "Измерено", CellData.GetDataType.DEVIATION: "Отклонение, %", CellData.GetDataType.DELTA_2: "Полудельта, %", CellData.GetDataType.SKO_PERCENTS: "СКО, %", CellData.GetDataType.STUDENT_95: "Доверительный интервал 0.95, %", CellData.GetDataType.STUDENT_99: "Доверительный интервал 0.99, %", CellData.GetDataType.STUDENT_999: "Доверительный интервал 0.999, %", # CellData.GetDataType.MEASURE_DATE: "Дата измерения", } def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) try: self.settings = settings.get_clb_autocalibration_settings() ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical( self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, ' 'удалите файл "settings.ini" и запустите программу заново') if ini_ok: self.settings.restore_qwidget_state(self) self.settings.restore_qwidget_state(self.ui.mainwindow_splitter) self.settings.restore_qwidget_state(self.ui.mainwindow_splitter_2) self.settings.restore_qwidget_state(self.ui.measures_table) self.ui.measures_table.setItemDelegate( TransparentPainterForWidget(self.ui.measures_table, "#d4d4ff")) self.ui.progress_bar_widget.setHidden(True) for i in range(CellData.GetDataType.COUNT): self.ui.displayed_data_type_combobox.addItem( MainWindow.displayed_data_to_text[i]) self.set_up_logger() self.ftdi_control = FtdiControl() self.clb_driver = clb_dll.clb_dll modbus_registers_count = 700 self.usb_driver = clb_dll.UsbDrv(self.clb_driver, modbus_registers_count * 2) self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED self.calibrator = clb_dll.ClbDrv(self.clb_driver) self.clb_state = clb.State.DISCONNECTED self.netvars = NetworkVariables(f"./{clb.CLB_CONFIG_NAME}", self.calibrator, a_variables_read_delay=0) self.clb_signal_off_timer = QtCore.QTimer() # noinspection PyTypeChecker self.clb_signal_off_timer.timeout.connect(self.close) self.SIGNAL_OFF_TIME_MS = 200 self.ignore_save = False self.current_configuration_path = "" self.measure_progress_bar_value = 0 self.tstlan_dialog = None self.graphs_dialog = None self.open_correction_tables = False self.show() self.measure_manager = MeasureManager(self.ui.measures_table, self.ui.measure_data_view, self.settings, self) self.open_configuration_by_name( self.settings.last_configuration_path) self.measure_conductor = MeasureConductor(self.calibrator, self.netvars, self.measure_manager, self.settings) self.measure_conductor.all_measures_done.connect(self.measure_done) self.measure_conductor.single_measure_started.connect( self.single_measure_started) self.measure_conductor.single_measure_done.connect( self.single_measure_done) self.measure_conductor.verify_flash_done.connect( self.verify_flash_done) self.connect_all() self.tick_timer = QtCore.QTimer(self) self.tick_timer.timeout.connect(self.tick) self.tick_timer.start(10) else: self.close() def connect_all(self): self.ui.lock_action.triggered.connect(self.lock_cell_button_clicked) self.ui.unlock_action.triggered.connect( self.unlock_cell_button_clicked) self.ui.lock_all_action.triggered.connect( self.lock_all_cells_button_clicked) self.ui.unlock_all_action.triggered.connect( self.unlock_all_cells_button_clicked) self.ui.show_equal_action.toggled.connect( self.show_equal_cell_configs_button_toggled) self.ui.switch_to_active_cell_action.setChecked( self.settings.switch_to_active_cell) self.ui.switch_to_active_cell_action.triggered.connect( self.switch_to_active_cell_action_toggled) self.ui.show_scheme_in_cell_action.setChecked( self.settings.show_scheme_in_cell) self.ui.show_scheme_in_cell_action.triggered.connect( self.show_scheme_in_cell_toggled) self.show_scheme_in_cell_toggled(self.settings.show_scheme_in_cell) self.ui.add_row_button.clicked.connect(self.add_row_button_clicked) self.ui.remove_row_button.clicked.connect( self.remove_row_button_clicked) self.ui.add_column_button.clicked.connect( self.add_column_button_clicked) self.ui.remove_column_button.clicked.connect( self.remove_column_button_clicked) self.ui.clear_table_button.clicked.connect( self.clear_table_button_clicked) self.ui.start_all_action.triggered.connect( self.start_all_measures_button_clicked) self.ui.continue_all_action.triggered.connect( self.continue_all_measures_button_clicked) self.ui.start_current_measure_button.clicked.connect( self.start_current_measure_button_clicked) self.ui.continue_current_measure_button.clicked.connect( self.continue_current_measure_button_clicked) self.ui.stop_all_action.triggered.connect( self.stop_measure_button_clicked) self.ui.flash_all_action.triggered.connect( self.flash_all_button_clicked) self.ui.verify_all_action.triggered.connect( self.verify_all_button_clicked) self.ui.read_correction_tables_action.triggered.connect( self.read_correction_tables_button_clicked) self.ui.stop_flash_verify_action.triggered.connect( self.stop_flash_verify_button_clicked) self.ui.get_correction_tables_from_file_action.triggered.connect( self.open_correction_tables_from_file) self.ui.measure_data_view.clicked.connect( self.measure_data_cell_clicked) self.ui.measure_data_view.customContextMenuRequested.connect( self.show_data_table_context_menu) self.ui.measures_table.customContextMenuRequested.connect( self.show_measures_table_context_menu) self.ui.enter_settings_action.triggered.connect(self.open_settings) self.ui.open_tstlan_action.triggered.connect(self.open_tstlan) self.ui.graphs_action.triggered.connect(self.open_graphs) self.ui.save_action.triggered.connect(self.save_configuration) self.ui.save_as_action.triggered.connect(self.save_configuration_as) self.ui.save_current_measure_button.clicked.connect( self.save_current_configuration) self.ui.open_cell_config_button.clicked.connect( self.open_cell_configuration) self.ui.open_action.triggered.connect(self.open_configuration) self.ui.new_configuration_action.triggered.connect( self.create_new_configuration) self.ui.clb_list_combobox.currentTextChanged.connect( self.connect_to_clb) self.ui.add_measure_button.clicked.connect( self.add_measure_button_clicked) self.ui.delete_measure_button.clicked.connect( self.remove_measure_button_clicked) self.ui.rename_measure_button.clicked.connect( self.rename_measure_button_clicked) self.ui.open_shared_measure_parameters_button.clicked.connect( self.open_shared_measure_parameters) self.ui.update_measure_status_button.clicked.connect( self.update_measure_status_button_clicked) self.ui.enable_all_button.clicked.connect( self.enable_all_button_clicked) self.ui.copy_cell_config_action.triggered.connect( self.copy_cell_config) self.ui.measure_data_view.addAction(self.ui.copy_cell_config_action) self.ui.paste_cell_config_action.triggered.connect( self.paste_cell_config) self.ui.measure_data_view.addAction(self.ui.paste_cell_config_action) self.ui.copy_cell_value_action.triggered.connect(self.copy_cell_value) self.ui.measure_data_view.addAction(self.ui.copy_cell_value_action) self.ui.paste_cell_value_action.triggered.connect( self.paste_cell_value) self.ui.measure_data_view.addAction(self.ui.paste_cell_value_action) self.ui.show_cell_graph_action.triggered.connect(self.open_cell_graph) self.ui.measure_data_view.addAction(self.ui.show_cell_graph_action) self.ui.flash_current_measure_action.triggered.connect( self.flash_table) self.ui.measure_data_view.addAction( self.ui.flash_current_measure_action) self.ui.verify_current_measure_action.triggered.connect( self.verify_table) self.ui.measure_data_view.addAction( self.ui.verify_current_measure_action) self.ui.verify_diapason_of_cell_action.triggered.connect( self.verify_diapason_of_cell) self.ui.measure_data_view.addAction( self.ui.verify_diapason_of_cell_action) self.ui.flash_diapason_of_cell_action.triggered.connect( self.flash_diapason_of_cell) self.ui.measure_data_view.addAction( self.ui.flash_diapason_of_cell_action) self.ui.meter_combobox.currentIndexChanged.connect(self.set_meter) self.ui.meter_settings_button.clicked.connect(self.open_meter_settings) self.ui.scheme_combobox.setCurrentIndex(self.settings.scheme_type) self.ui.scheme_combobox.currentIndexChanged.connect( self.set_scheme_type) self.set_scheme_type(self.ui.scheme_combobox.currentIndex()) self.ui.displayed_data_type_combobox.currentIndexChanged.connect( self.set_displayed_data) self.ui.calculate_divider_coefficients.triggered.connect( self.calculate_divider_coefficients_button_clicked) self.ui.open_about_action.triggered.connect(self.open_about) def set_up_logger(self): log = qt_utils.QTextEditLogger(self.ui.log_text_edit) log.setFormatter( logging.Formatter('%(asctime)s - %(message)s', datefmt='%H:%M:%S')) file_log = RotatingFileHandler("autocalibration.log", maxBytes=30 * 1024 * 1024, backupCount=3, encoding='utf8') file_log.setLevel(logging.DEBUG) file_log.setFormatter( logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%H:%M:%S')) logging.getLogger().addHandler(file_log) logging.getLogger().addHandler(log) logging.getLogger().setLevel(logging.DEBUG) def lock_interface(self, a_lock: bool): self.ui.new_configuration_action.setDisabled(a_lock) self.ui.open_action.setDisabled(a_lock) self.ui.save_action.setDisabled(a_lock) self.ui.save_as_action.setDisabled(a_lock) self.ui.start_all_action.setDisabled(a_lock) self.ui.continue_all_action.setDisabled(a_lock) self.ui.flash_all_action.setDisabled(a_lock) self.ui.verify_all_action.setDisabled(a_lock) self.ui.read_correction_tables_action.setDisabled(a_lock) self.ui.stop_flash_verify_action.setDisabled(a_lock) self.ui.lock_action.setDisabled(a_lock) self.ui.unlock_action.setDisabled(a_lock) self.ui.lock_all_action.setDisabled(a_lock) self.ui.unlock_all_action.setDisabled(a_lock) self.ui.save_current_measure_button.setDisabled(a_lock) self.ui.start_current_measure_button.setDisabled(a_lock) self.ui.continue_current_measure_button.setDisabled(a_lock) self.ui.add_row_button.setDisabled(a_lock) self.ui.remove_row_button.setDisabled(a_lock) self.ui.add_column_button.setDisabled(a_lock) self.ui.remove_column_button.setDisabled(a_lock) self.ui.clear_table_button.setDisabled(a_lock) self.ui.clb_list_combobox.setDisabled(a_lock) self.ui.meter_combobox.setDisabled(a_lock) self.ui.scheme_combobox.setDisabled(a_lock) self.ui.add_measure_button.setDisabled(a_lock) self.ui.delete_measure_button.setDisabled(a_lock) self.ui.rename_measure_button.setDisabled(a_lock) self.ui.update_measure_status_button.setDisabled(a_lock) self.ui.enable_all_button.setDisabled(a_lock) self.ui.paste_cell_value_action.setDisabled(a_lock) self.ui.paste_cell_config_action.setDisabled(a_lock) self.ui.flash_current_measure_action.setDisabled(a_lock) self.ui.verify_current_measure_action.setDisabled(a_lock) self.ui.flash_diapason_of_cell_action.setDisabled(a_lock) self.ui.verify_diapason_of_cell_action.setDisabled(a_lock) self.ui.progress_bar_widget.setHidden(not a_lock) self.measure_manager.lock_interface(a_lock) def gui_tick(self): self.progress_bars_handling() correction_enabled = not self.netvars.ui_correct_off.get() correction_enabled_ui = self.ui.correction_action.isChecked() if not correction_enabled == correction_enabled_ui: self.ui.correction_action.setChecked(correction_enabled) def tick(self): self.measure_conductor.tick() self.usb_driver.tick() self.gui_tick() if self.usb_driver.is_dev_list_changed(): self.ui.clb_list_combobox.clear() for clb_name in self.usb_driver.get_dev_list(): self.ui.clb_list_combobox.addItem(clb_name) if self.usb_driver.is_status_changed(): self.usb_state = self.usb_driver.get_status() current_state = clb.State.DISCONNECTED if self.usb_state == clb_dll.UsbDrv.UsbState.CONNECTED: if self.calibrator.signal_enable_changed(): self.signal_enable_changed.emit(self.calibrator.signal_enable) if not self.calibrator.signal_enable: current_state = clb.State.STOPPED elif not self.calibrator.is_signal_ready(): current_state = clb.State.WAITING_SIGNAL else: current_state = clb.State.READY if self.clb_state != current_state: self.clb_state = current_state self.calibrator.state = current_state self.usb_status_changed.emit(self.clb_state) def connect_to_clb(self, a_clb_name): self.calibrator.connect(a_clb_name) def count_measure_length(self, a_iteration_type: MeasureManager.IterationType): measure_iterator = self.measure_manager.get_measure_iterator( a_iteration_type) seconds_count = 0 if measure_iterator is not None: cell_position = measure_iterator.get() while cell_position is not None: cell_config = self.measure_manager.get_cell_config( *cell_position) seconds_count += cell_config.measure_delay seconds_count += cell_config.measure_time measure_iterator.next() cell_position = measure_iterator.get() return seconds_count def set_up_progress_bars_for_measure(self, a_measures_total_length): self.ui.measure_progress_bar.setMaximum(a_measures_total_length) self.ui.measure_progress_bar.setFormat("%v с. / %m с. (%p%)") self.ui.curent_cell_progress_bar.setFormat("%v с. / %m с. (%p%)") def start_measure(self, a_iteration_type: MeasureManager.IterationType): measure_iterator = self.measure_manager.get_measure_iterator( a_iteration_type) if measure_iterator is not None: # Это происходит, когда нет выделенных ячеек if measure_iterator.get() is not None: if self.save_configuration(): self.lock_interface(True) self.set_up_progress_bars_for_measure( self.count_measure_length(a_iteration_type)) if a_iteration_type in ( MeasureManager.IterationType.START_ALL, MeasureManager.IterationType.CONTINUE_ALL): auto_flash_to_calibrator = True else: auto_flash_to_calibrator = False self.measure_conductor.start(measure_iterator, auto_flash_to_calibrator) def progress_bars_handling(self): if self.measure_conductor.is_started(): time_passed = self.measure_conductor.get_current_cell_time_passed() self.ui.curent_cell_progress_bar.setValue(time_passed) self.ui.measure_progress_bar.setValue( self.measure_progress_bar_value + time_passed) elif self.measure_conductor.is_correction_flash_verify_started(): current, full = self.measure_conductor.get_flash_progress() self.ui.curent_cell_progress_bar.setValue(current) self.ui.measure_progress_bar.setValue(full) def single_measure_started(self): self.ui.curent_cell_progress_bar.setMaximum( self.measure_conductor.get_current_cell_time_duration()) def single_measure_done(self): # "Переливаем" прогресс маленького прогресс бара в большой self.measure_progress_bar_value += self.ui.curent_cell_progress_bar.maximum( ) self.ui.curent_cell_progress_bar.setValue(0) if not self.save_current_configuration(): logging.warning( "Не удалось сохранить результат после завершения измерения ячейки" ) def measure_done(self): self.ui.curent_cell_progress_bar.setValue(0) self.ui.curent_cell_progress_bar.resetFormat() self.ui.measure_progress_bar.setValue(0) self.ui.measure_progress_bar.resetFormat() self.measure_progress_bar_value = 0 self.lock_interface(False) def start_all_measures_button_clicked(self, _): self.start_measure(MeasureManager.IterationType.START_ALL) def continue_all_measures_button_clicked(self, _): self.start_measure(MeasureManager.IterationType.CONTINUE_ALL) def start_current_measure_button_clicked(self, _): self.start_measure(MeasureManager.IterationType.START_CURRENT) def continue_current_measure_button_clicked(self, _): self.start_measure(MeasureManager.IterationType.CONTINUE_CURRENT) def stop_measure_button_clicked(self, _): self.measure_conductor.stop() def copy_cell_config(self): self.measure_manager.copy_cell_config() def paste_cell_config(self): self.measure_manager.paste_cell_config() def copy_cell_value(self): self.measure_manager.copy_cell_value() def paste_cell_value(self): self.measure_manager.paste_cell_value() def lock_gui_while_flash(self): self.lock_interface(True) self.ui.stop_flash_verify_action.setDisabled(False) self.ui.measure_progress_bar.setMaximum(100) # self.ui.measure_progress_bar.setValue(0) self.ui.curent_cell_progress_bar.setMaximum(100) # self.ui.curent_cell_progress_bar.setValue(0) def flash_table(self): if self.calibrator.state == clb.State.STOPPED: current_measure = self.measure_manager.get_current_measure() if current_measure is not None: if self.measure_conductor.start_flash([current_measure]): self.lock_gui_while_flash() else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def flash_diapason_of_cell(self): if self.calibrator.state == clb.State.STOPPED: current_measure = self.measure_manager.get_current_measure() if current_measure is not None: selected_cell = self.measure_manager.get_only_selected_cell() if selected_cell and selected_cell.row() != 0: amplitude = self.measure_manager.get_amplitude( current_measure, selected_cell.row()) if self.measure_conductor.start_flash([current_measure], amplitude): self.lock_gui_while_flash() else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def verify_table(self): if self.calibrator.state == clb.State.STOPPED: current_measure = self.measure_manager.get_current_measure() if current_measure is not None: if self.measure_conductor.start_verify([current_measure]): self.lock_gui_while_flash() else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def verify_diapason_of_cell(self): if self.calibrator.state == clb.State.STOPPED: current_measure = self.measure_manager.get_current_measure() if current_measure is not None: selected_cell = self.measure_manager.get_only_selected_cell() if selected_cell and selected_cell.row() != 0: amplitude = self.measure_manager.get_amplitude( current_measure, selected_cell.row()) if self.measure_conductor.start_verify([current_measure], amplitude): self.lock_gui_while_flash() else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def flash_all_button_clicked(self): if self.calibrator.state == clb.State.STOPPED: enabled_measures = self.measure_manager.get_enabled_measures() if enabled_measures: if self.measure_conductor.start_flash(enabled_measures): self.lock_gui_while_flash() else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def verify_all_button_clicked(self): if self.calibrator.state == clb.State.STOPPED: enabled_measures = self.measure_manager.get_enabled_measures() if enabled_measures: if self.measure_conductor.start_verify(enabled_measures): self.lock_gui_while_flash() else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def read_correction_tables_button_clicked(self): if self.calibrator.state == clb.State.STOPPED: enabled_measures = self.measure_manager.get_enabled_measures() if enabled_measures: if self.measure_conductor.start_read_correction_to_tables( enabled_measures): self.lock_gui_while_flash() self.open_correction_tables = True else: logging.error( "Калибратор не подключен, либо не находится в состоянии покоя") def stop_flash_verify_button_clicked(self): self.measure_conductor.stop_flash_verify() @utils.exception_decorator def verify_flash_done(self): self.lock_interface(False) self.ui.measure_progress_bar.setValue(0) self.ui.curent_cell_progress_bar.setValue(0) if self.open_correction_tables: self.open_correction_tables = False correction_tables = self.measure_conductor.get_correction_tables() if correction_tables: correct_tables_dialog = CorrectionTablesDialog( correction_tables, self.settings) correct_tables_dialog.exec() @utils.exception_decorator def open_correction_tables_from_file(self, _): tables_filename, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Открыть таблицы коррекции", "", "Таблицы коррекции (*.ct)") if tables_filename: with open(tables_filename, "r") as tables_file: correction_tables = json.loads(tables_file.read()) if correction_tables: correct_tables_dialog = CorrectionTablesDialog( correction_tables, self.settings) correct_tables_dialog.exec() def show_data_table_context_menu(self): menu = QtWidgets.QMenu(self) menu.addAction(self.ui.copy_cell_value_action) menu.addAction(self.ui.paste_cell_value_action) menu.addAction(self.ui.copy_cell_config_action) menu.addAction(self.ui.paste_cell_config_action) menu.insertSeparator(self.ui.copy_cell_config_action) menu.addAction(self.ui.show_cell_graph_action) menu.insertSeparator(self.ui.show_cell_graph_action) menu.addAction(self.ui.flash_current_measure_action) menu.addAction(self.ui.verify_current_measure_action) menu.insertSeparator(self.ui.flash_current_measure_action) menu.addAction(self.ui.flash_diapason_of_cell_action) menu.addAction(self.ui.verify_diapason_of_cell_action) menu.insertSeparator(self.ui.flash_diapason_of_cell_action) # add other required actions menu.popup(QtGui.QCursor.pos()) def open_measure_folder(self): if self.current_configuration_path: path = self.current_configuration_path.replace("/", "\\") os_system(f'explorer.exe "{path}"') def show_measures_table_context_menu(self): menu = QtWidgets.QMenu(self) open_measure_folder_action = QtWidgets.QAction( "Открыть каталог измерения", self) open_measure_folder_action.triggered.connect(self.open_measure_folder) menu.addAction(open_measure_folder_action) # add other required actions menu.popup(QtGui.QCursor.pos()) @utils.exception_decorator def add_measure_button_clicked(self, _): self.measure_manager.new_measure() if self.current_configuration_path: self.save_current_configuration() else: self.save_configuration() @utils.exception_decorator def remove_measure_button_clicked(self, _): self.measure_manager.remove_measure(self.current_configuration_path) def enable_all_button_clicked(self, _): self.measure_manager.enable_all_measures() @utils.exception_decorator def rename_measure_button_clicked(self, _): self.measure_manager.rename_current_measure( self.current_configuration_path) def update_measure_status_button_clicked(self, _): self.measure_manager.update_all_measures_status() def show_equal_cell_configs_button_toggled(self, a_enable: bool): self.measure_manager.show_equal_cell_configs(a_enable) def switch_to_active_cell_action_toggled(self, a_enable: bool): self.settings.switch_to_active_cell = int(a_enable) def show_scheme_in_cell_toggled(self, a_enable: bool): if a_enable: self.ui.measure_data_view.setItemDelegate( SchemeInCellPainter(self.ui.measure_data_view, "#d4d4ff")) else: self.ui.measure_data_view.setItemDelegate( TransparentPainterForView(self.ui.measure_data_view, "#d4d4ff")) def measure_data_cell_clicked(self, index: QtCore.QModelIndex): if self.ui.show_equal_action.isChecked(): self.measure_manager.set_cell_to_compare(index) def lock_cell_button_clicked(self): self.measure_manager.lock_selected_cells(True) def unlock_cell_button_clicked(self): self.measure_manager.lock_selected_cells(False) def lock_all_cells_button_clicked(self): self.measure_manager.lock_all_cells(True) def unlock_all_cells_button_clicked(self): self.measure_manager.lock_all_cells(False) def add_row_button_clicked(self, _): self.measure_manager.add_row_to_current_measure() def remove_row_button_clicked(self, _): self.measure_manager.remove_row_from_current_measure() def add_column_button_clicked(self, _): self.measure_manager.add_column_to_current_measure() def remove_column_button_clicked(self, _): self.measure_manager.remove_column_from_current_measure() def clear_table_button_clicked(self, _): self.measure_manager.clear_table_content() @utils.exception_decorator def open_tstlan(self, _): # noinspection PyTypeChecker if self.tstlan_dialog is None: self.tstlan_dialog = TstlanDialog(self.netvars, self.calibrator, self.settings) self.tstlan_dialog.exec() self.tstlan_dialog = None else: self.tstlan_dialog.activateWindow() @utils.exception_decorator def open_graphs(self, _): if self.graphs_dialog is None: graphs_data = self.measure_manager.get_data_for_graphs() if graphs_data: self.graphs_dialog = GraphDialog(graphs_data, self.settings) self.graphs_dialog.exec() self.graphs_dialog = None else: self.graphs_dialog.activateWindow() @utils.exception_decorator def open_cell_graph(self, _): graphs_data = self.measure_manager.get_cell_measurement_graph() if graphs_data: graph_dialog = GraphDialog(graphs_data, self.settings) graph_dialog.exec() @utils.exception_decorator def open_settings(self, _): settings_dialog = SettingsDialog(self.settings, self) settings_dialog.exec() def open_about(self): about_dialog = AboutDialog(self) about_dialog.exec() def open_shared_measure_parameters(self, _): self.measure_manager.open_shared_measure_parameters() def calculate_divider_coefficients_button_clicked(self, _): logging.error("Не реализовано ¯\\_(ツ)_/¯") def open_cell_configuration(self): self.measure_manager.open_cell_configuration() def set_meter(self, a_index: int): self.measure_manager.set_meter(MeterType(a_index)) def set_scheme_type(self, a_index: int): self.measure_manager.set_scheme(SchemeType(a_index), self.ftdi_control) self.settings.scheme_type = a_index def open_meter_settings(self): self.measure_manager.open_meter_settings() def set_displayed_data(self, a_displayed_data: int): self.measure_manager.set_displayed_data( CellData.GetDataType(a_displayed_data)) def save_configuration(self): result = True if self.current_configuration_path: if not self.measure_manager.is_saved(): result = self.save_configuration_by_name( self.current_configuration_path) else: result = self.save_configuration_as() return result def save_configuration_as(self): result = True # noinspection PyTypeChecker config_dir = QtWidgets.QFileDialog.getExistingDirectory( self, "Выберите каталог конфигураций", self.current_configuration_path) if config_dir: config_filename = f"{config_dir}" if self.save_configuration_by_name(config_filename): self.open_configuration_by_name(config_filename) pass else: result = False else: result = False return result def save_current_configuration(self): result = True if self.current_configuration_path: if not self.measure_manager.is_current_saved(): if not self.measure_manager.save_current( self.current_configuration_path): QtWidgets.QMessageBox.critical( self, "Ошибка", "Не удалось сохранить измерение", QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) result = False else: QtWidgets.QMessageBox.critical(self, "Ошибка", f"Конфигурация не сохранена", QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) return result def save_configuration_by_name(self, a_folder: str): result = True if self.measure_manager.save(a_folder): self.current_configuration_path = a_folder self.settings.last_configuration_path = a_folder self.setWindowTitle(self.current_configuration_path) else: QtWidgets.QMessageBox.critical( self, "Ошибка", f"Не удалось сохранить конфигурации в каталоге {a_folder}", QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) result = False return result def reset_measure_manager(self): self.measure_manager = MeasureManager(self.ui.measures_table, self.ui.measure_data_view, self.settings, self) self.set_scheme_type(self.ui.scheme_combobox.currentIndex()) self.measure_conductor = MeasureConductor(self.calibrator, self.netvars, self.measure_manager, self.settings) self.measure_conductor.all_measures_done.connect(self.measure_done) self.measure_conductor.single_measure_started.connect( self.single_measure_started) self.measure_conductor.single_measure_done.connect( self.single_measure_done) self.measure_conductor.verify_flash_done.connect( self.verify_flash_done) def create_new_configuration(self): cancel_open = False if self.current_configuration_path: if not self.measure_manager.is_saved(): answer = self.close_configuration() if answer == MainWindow.CloseConfigOptions.SAVE: if not self.save_configuration(): cancel_open = True elif answer == MainWindow.CloseConfigOptions.CANCEL: cancel_open = True if not cancel_open: self.current_configuration_path = "" self.reset_measure_manager() def open_configuration(self): cancel_open = False if self.current_configuration_path: if not self.measure_manager.is_saved(): answer = self.close_configuration() if answer == MainWindow.CloseConfigOptions.SAVE: if not self.save_configuration(): cancel_open = True elif answer == MainWindow.CloseConfigOptions.CANCEL: cancel_open = True if not cancel_open: config_filename = QtWidgets.QFileDialog.getExistingDirectory( self, "Выберите каталог конфигураций", self.settings.last_configuration_path) if config_filename: self.settings.last_configuration_path = config_filename self.open_configuration_by_name(config_filename) def open_configuration_by_name(self, a_folder: str): try: if self.measure_manager.load_from_file(a_folder): self.current_configuration_path = a_folder self.setWindowTitle(self.current_configuration_path) elif a_folder: QtWidgets.QMessageBox.critical( self, "Ошибка", f'Не удалось найти файлы конфигураций в каталоге "{a_folder}"', QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) except FileNotFoundError: QtWidgets.QMessageBox.critical( self, "Ошибка", f'Не удалось найти каталог "{a_folder}"', QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) @staticmethod def close_configuration() -> CloseConfigOptions: msgbox = QtWidgets.QMessageBox() msgbox.setWindowTitle("Предупреждение") msgbox.setText("Текущая конфигурация не сохранена. Выберите действие") save_button = msgbox.addButton("Сохранить", QtWidgets.QMessageBox.YesRole) no_save_button = msgbox.addButton("Не сохранять", QtWidgets.QMessageBox.AcceptRole) _ = msgbox.addButton("Отмена", QtWidgets.QMessageBox.AcceptRole) msgbox.exec() if msgbox.clickedButton() == save_button: return MainWindow.CloseConfigOptions.SAVE elif msgbox.clickedButton() == no_save_button: return MainWindow.CloseConfigOptions.DONT_SAVE else: return MainWindow.CloseConfigOptions.CANCEL def closeEvent(self, a_event: QtGui.QCloseEvent): if not self.measure_manager.is_saved() and not self.ignore_save: answer = self.close_configuration() if answer == MainWindow.CloseConfigOptions.SAVE: if self.save_configuration_by_name( self.current_configuration_path): a_event.ignore() self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS) else: QtWidgets.QMessageBox.critical( self, "Ошибка", "Не удалось сохранить конфигурацию") a_event.ignore() elif answer == MainWindow.CloseConfigOptions.DONT_SAVE: self.ignore_save = True self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS) a_event.ignore() else: a_event.ignore() else: if self.calibrator.signal_enable: self.calibrator.signal_enable = False self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS) a_event.ignore() else: self.settings.save_qwidget_state(self.ui.mainwindow_splitter) self.settings.save_qwidget_state(self.ui.mainwindow_splitter_2) self.settings.save_qwidget_state(self.ui.measures_table) self.settings.save_qwidget_state(self) a_event.accept()
def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) self.loader = QtGui.QMovie(":/icons/gif/loader2.gif") self.loader.setScaledSize(QtCore.QSize(132, 99)) self.ui.loader_label.setMovie(self.loader) try: self.settings = Settings("./settings.ini", [ Settings.VariableInfo( a_name="fixed_step_list", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_FLOAT, a_default=[0.0001, 0.01, 0.1, 1, 10, 20, 100]), Settings.VariableInfo(a_name="checkbox_states", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="fixed_step_idx", a_section="PARAMETERS", a_type=Settings.ValueType.INT), Settings.VariableInfo(a_name="rough_step", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.5), Settings.VariableInfo(a_name="common_step", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.05), Settings.VariableInfo(a_name="exact_step", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.002), Settings.VariableInfo(a_name="tstlan_update_time", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.2), Settings.VariableInfo(a_name="tstlan_show_marks", a_section="PARAMETERS", a_type=Settings.ValueType.INT, a_default=0), Settings.VariableInfo(a_name="tstlan_marks", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="tstlan_graphs", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="tests_repeat_count", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="tests_collapsed_states", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="last_save_results_folder", a_section="PARAMETERS", a_type=Settings.ValueType.STRING), Settings.VariableInfo(a_name="aux_correction_deviation", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=10), Settings.VariableInfo(a_name="aux_deviation", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=2), Settings.VariableInfo(a_name="aux_voltage_25_discretes_60v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=18), Settings.VariableInfo(a_name="aux_voltage_230_discretes_60v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=61.2), Settings.VariableInfo(a_name="aux_voltage_25_discretes_200v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=61), Settings.VariableInfo(a_name="aux_voltage_230_discretes_200v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=215), Settings.VariableInfo(a_name="aux_voltage_25_discretes_600v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=165), Settings.VariableInfo(a_name="aux_voltage_230_discretes_600v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=605), Settings.VariableInfo(a_name="aux_voltage_25_discretes_4v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=1.73), Settings.VariableInfo(a_name="aux_voltage_230_discretes_4v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=4.6), ]) ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical( self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, ' 'удалите файл "settings.ini" и запустите программу заново') if ini_ok: self.restoreGeometry( self.settings.get_last_geometry(self.__class__.__name__)) self.ui.splitter.restoreState( self.settings.get_last_geometry( self.ui.splitter.__class__.__name__ + "1")) self.ui.splitter_2.restoreState( self.settings.get_last_geometry( self.ui.splitter_2.__class__.__name__ + "2")) self.ui.tests_tree.header().restoreState( self.settings.get_last_geometry( self.ui.tests_tree.__class__.__name__)) self.set_up_logger() self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path) modbus_registers_count = 700 self.usb_driver = clb_dll.UsbDrv(self.clb_driver, modbus_registers_count * 2) self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED self.calibrator = clb_dll.ClbDrv(self.clb_driver) self.clb_state = clb.State.DISCONNECTED self.netvars = NetworkVariables(cfg.CLB_CONFIG_PATH, self.calibrator) self.netvars_db = NetvarsDatabase("./netvars.db", self) self.clb_signal_off_timer = QtCore.QTimer() # noinspection PyTypeChecker self.clb_signal_off_timer.timeout.connect(self.close) self.SIGNAL_OFF_TIME_MS = 200 self.previous_id = 0 self.ui.enter_settings_action.triggered.connect(self.open_settings) self.source_mode_widget = self.set_up_source_mode_widget() self.show() self.tests = tests_factory.create_tests(self.calibrator, self.netvars, self.netvars_db, self.settings) self.tests_widget = TestsTreeWidget(self.tests, self.ui.tests_tree, self.settings) self.tests_widget.show_graph_requested.connect( self.show_test_graph) self.tests_widget.show_errors_requested.connect( self.show_test_errors) self.graphs_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {} self.errors_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {} self.test_conductor = TestsConductor(self.tests) self.ui.autocheck_start_button.clicked.connect( self.autocheck_button_clicked) self.test_conductor.tests_done.connect(self.stop_autocheck) self.test_conductor.test_status_changed.connect( self.set_test_status) self.source_mode_widget.ui.open_tstlan_button.clicked.connect( self.open_tstlan) self.ui.save_button.clicked.connect(self.save_button_clicked) self.ui.load_button.clicked.connect(self.load_results) self.ui.clear_results_button.clicked.connect(self.clear_results) self.tick_timer = QtCore.QTimer(self) self.tick_timer.timeout.connect(self.tick) self.tick_timer.start(10) else: self.close()
class MainWindow(QtWidgets.QMainWindow): clb_list_changed = QtCore.pyqtSignal([list]) usb_status_changed = QtCore.pyqtSignal(clb.State) signal_enable_changed = QtCore.pyqtSignal(bool) TEST_START_ROW = 1 CHECK_BOX_COLUMN = 0 STATUS_COLUMN = 2 def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) self.loader = QtGui.QMovie(":/icons/gif/loader2.gif") self.loader.setScaledSize(QtCore.QSize(132, 99)) self.ui.loader_label.setMovie(self.loader) try: self.settings = Settings("./settings.ini", [ Settings.VariableInfo( a_name="fixed_step_list", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_FLOAT, a_default=[0.0001, 0.01, 0.1, 1, 10, 20, 100]), Settings.VariableInfo(a_name="checkbox_states", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="fixed_step_idx", a_section="PARAMETERS", a_type=Settings.ValueType.INT), Settings.VariableInfo(a_name="rough_step", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.5), Settings.VariableInfo(a_name="common_step", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.05), Settings.VariableInfo(a_name="exact_step", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.002), Settings.VariableInfo(a_name="tstlan_update_time", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=0.2), Settings.VariableInfo(a_name="tstlan_show_marks", a_section="PARAMETERS", a_type=Settings.ValueType.INT, a_default=0), Settings.VariableInfo(a_name="tstlan_marks", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="tstlan_graphs", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="tests_repeat_count", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="tests_collapsed_states", a_section="PARAMETERS", a_type=Settings.ValueType.LIST_INT), Settings.VariableInfo(a_name="last_save_results_folder", a_section="PARAMETERS", a_type=Settings.ValueType.STRING), Settings.VariableInfo(a_name="aux_correction_deviation", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=10), Settings.VariableInfo(a_name="aux_deviation", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=2), Settings.VariableInfo(a_name="aux_voltage_25_discretes_60v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=18), Settings.VariableInfo(a_name="aux_voltage_230_discretes_60v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=61.2), Settings.VariableInfo(a_name="aux_voltage_25_discretes_200v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=61), Settings.VariableInfo(a_name="aux_voltage_230_discretes_200v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=215), Settings.VariableInfo(a_name="aux_voltage_25_discretes_600v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=165), Settings.VariableInfo(a_name="aux_voltage_230_discretes_600v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=605), Settings.VariableInfo(a_name="aux_voltage_25_discretes_4v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=1.73), Settings.VariableInfo(a_name="aux_voltage_230_discretes_4v", a_section="PARAMETERS", a_type=Settings.ValueType.FLOAT, a_default=4.6), ]) ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical( self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, ' 'удалите файл "settings.ini" и запустите программу заново') if ini_ok: self.restoreGeometry( self.settings.get_last_geometry(self.__class__.__name__)) self.ui.splitter.restoreState( self.settings.get_last_geometry( self.ui.splitter.__class__.__name__ + "1")) self.ui.splitter_2.restoreState( self.settings.get_last_geometry( self.ui.splitter_2.__class__.__name__ + "2")) self.ui.tests_tree.header().restoreState( self.settings.get_last_geometry( self.ui.tests_tree.__class__.__name__)) self.set_up_logger() self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path) modbus_registers_count = 700 self.usb_driver = clb_dll.UsbDrv(self.clb_driver, modbus_registers_count * 2) self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED self.calibrator = clb_dll.ClbDrv(self.clb_driver) self.clb_state = clb.State.DISCONNECTED self.netvars = NetworkVariables(cfg.CLB_CONFIG_PATH, self.calibrator) self.netvars_db = NetvarsDatabase("./netvars.db", self) self.clb_signal_off_timer = QtCore.QTimer() # noinspection PyTypeChecker self.clb_signal_off_timer.timeout.connect(self.close) self.SIGNAL_OFF_TIME_MS = 200 self.previous_id = 0 self.ui.enter_settings_action.triggered.connect(self.open_settings) self.source_mode_widget = self.set_up_source_mode_widget() self.show() self.tests = tests_factory.create_tests(self.calibrator, self.netvars, self.netvars_db, self.settings) self.tests_widget = TestsTreeWidget(self.tests, self.ui.tests_tree, self.settings) self.tests_widget.show_graph_requested.connect( self.show_test_graph) self.tests_widget.show_errors_requested.connect( self.show_test_errors) self.graphs_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {} self.errors_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {} self.test_conductor = TestsConductor(self.tests) self.ui.autocheck_start_button.clicked.connect( self.autocheck_button_clicked) self.test_conductor.tests_done.connect(self.stop_autocheck) self.test_conductor.test_status_changed.connect( self.set_test_status) self.source_mode_widget.ui.open_tstlan_button.clicked.connect( self.open_tstlan) self.ui.save_button.clicked.connect(self.save_button_clicked) self.ui.load_button.clicked.connect(self.load_results) self.ui.clear_results_button.clicked.connect(self.clear_results) self.tick_timer = QtCore.QTimer(self) self.tick_timer.timeout.connect(self.tick) self.tick_timer.start(10) else: self.close() def set_up_logger(self): log = QTextEditLogger(self, self.ui.log_text_edit) log.setFormatter( logging.Formatter('%(asctime)s - %(message)s', datefmt='%H:%M:%S')) logging.getLogger().addHandler(log) # logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.INFO) # logging.getLogger().setLevel(logging.WARN) def set_up_source_mode_widget(self) -> SourceModeWidget: source_mode_widget = SourceModeWidget(self.settings, self.calibrator, self.netvars, self) self.clb_list_changed.connect(source_mode_widget.update_clb_list) self.usb_status_changed.connect(source_mode_widget.update_clb_status) self.signal_enable_changed.connect( source_mode_widget.signal_enable_changed) self.ui.source_mode_layout.addWidget(source_mode_widget) return source_mode_widget def tick(self): self.usb_tick() self.test_conductor.tick() def usb_tick(self): self.usb_driver.tick() if self.usb_driver.is_dev_list_changed(): self.clb_list_changed.emit(self.usb_driver.get_dev_list()) if self.usb_driver.is_status_changed(): self.usb_state = self.usb_driver.get_status() current_state = clb.State.DISCONNECTED if self.usb_state == clb_dll.UsbDrv.UsbState.CONNECTED: if self.calibrator.signal_enable_changed(): self.signal_enable_changed.emit(self.calibrator.signal_enable) if not self.calibrator.signal_enable: current_state = clb.State.STOPPED elif not self.calibrator.is_signal_ready(): current_state = clb.State.WAITING_SIGNAL else: current_state = clb.State.READY if self.clb_state != current_state: self.clb_state = current_state self.calibrator.state = current_state self.usb_status_changed.emit(self.clb_state) current_id = self.netvars.id.get() if current_id != self.previous_id: if current_id != 0: self.previous_id = current_id self.clear_results() def lock_interface(self, a_lock): self.source_mode_widget.ui.control_box.setDisabled(a_lock) self.tests_widget.lock_interface(a_lock) self.ui.load_button.setDisabled(a_lock) self.ui.save_button.setDisabled(a_lock) self.ui.clear_results_button.setDisabled(a_lock) def autocheck_button_clicked(self): try: if self.test_conductor.started(): self.test_conductor.stop() self.stop_autocheck() else: self.start_autocheck() except Exception as err: logging.debug(utils.exception_handler(err)) def start_autocheck(self): if self.calibrator.state != clb.State.DISCONNECTED: aux_group_enabled = self.tests_widget.is_group_enabled( "Предварительные стабилизаторы") if aux_group_enabled is None: logging.warning( 'Группа Предварительные стабилизаторы" не найдена') elif self.netvars.software_revision.get( ) < 295 and aux_group_enabled: QtWidgets.QMessageBox.warning( self, "Ошибка", "Тест предварительных стабилизаторов доступен для " "прошивок старше 294 ревизии", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.Yes) elif self.netvars.source_manual_mode_password.get( ) != clb.MANUAL_MODE_ENABLE_PASSWORD: self.lock_interface(True) self.test_conductor.set_enabled_tests( self.tests_widget.get_tests_repeat_count()) self.ui.autocheck_start_button.setText("Остановить") self.test_conductor.start() self.ui.loader_label.show() self.loader.start() else: logging.warning( "Включен ручной режим. Перезагрузите калибратор, чтобы запустить проверку" ) else: logging.warning( "Калибратор не подключен, невозможно провести проверку") def stop_autocheck(self): self.lock_interface(False) self.ui.autocheck_start_button.setText("Старт") logging.info("Проверка завершена") self.ui.loader_label.hide() self.loader.stop() def set_test_status(self, a_group_name, a_test_name: str, a_status: tests_base.ClbTest.Status, a_success_count: int): try: self.tests_widget.set_test_status(a_group_name, a_test_name, a_status, a_success_count) except AssertionError as err: logging.debug(utils.exception_handler(err)) def open_tstlan(self): try: tstlan_dialog = TstlanDialog(self.netvars, self.calibrator, self.settings, self) tstlan_dialog.exec() except Exception as err: logging.debug(utils.exception_handler(err)) def show_test_graph(self, a_group: str, a_name: str): try: graph_data = self.test_conductor.get_test_graph(a_group, a_name) if graph_data: try: graphs_dialog = self.graphs_dialogs[(a_group, a_name)] graphs_dialog.activateWindow() except KeyError: graphs_dialog = TestGraphDialog(graph_data, self.settings, self) graphs_dialog.setWindowTitle( f'Графики теста "{a_group}: {a_name}"') self.graphs_dialogs[(a_group, a_name)] = graphs_dialog self.test_conductor.graphs_have_been_updated.connect( graphs_dialog.update_graphs) graphs_dialog.exec() del self.graphs_dialogs[(a_group, a_name)] else: logging.warning("График для выбранного измерения не создан") except Exception as err: logging.debug(utils.exception_handler(err)) def show_test_errors(self, a_group: str, a_name: str): try: errors_list = self.test_conductor.get_test_errors(a_group, a_name) has_errors = True if any(error != "" for error in errors_list) else False if has_errors: try: errors_dialog = self.errors_dialogs[(a_group, a_name)] errors_dialog.activateWindow() except KeyError: nl = "\n" errors_list = [ f'<p style=" color:#ff0000;">Тест №{num + 1}</p>{error.replace(nl, "<br>")}' for num, error in enumerate(errors_list) ] errors_dialog = DialogWithText(errors_list, self.settings, self) errors_dialog.setWindowTitle( f'Ошибки теста "{a_group}: {a_name}"') self.errors_dialogs[(a_group, a_name)] = errors_dialog errors_dialog.exec() del self.errors_dialogs[(a_group, a_name)] else: logging.warning("Выбранный тест не содержит ошибок") except Exception as err: logging.debug(utils.exception_handler(err)) @utils.exception_decorator def save_button_clicked(self, _): suggest_filename = f"{QtCore.QDate.currentDate().toString('yyyyMMdd')} N4-25 №{self.netvars.id.get()}" chosen_file, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Сохранить результаты", f"{self.settings.last_save_results_folder}/{suggest_filename}", "Результаты проверки (*.car)") if chosen_file != "": results = {} for test in self.tests: test_results = self.test_conductor.get_test_results( test.group(), test.name()) results[ f"{test.group()}:{test.name()}"] = test_results.data_to_serialize( ) results["log"] = self.ui.log_text_edit.toPlainText() with open(chosen_file, 'w') as file: file.write(json.dumps(results, indent=4)) @utils.exception_decorator def load_results(self, _): chosen_file, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Выберите файл", self.settings.last_save_results_folder, "Результаты проверки (*.car)") if chosen_file != "": self.settings.last_save_results_folder = chosen_file[:chosen_file. rfind("/")] with open(chosen_file, 'r') as file: test_results: Dict[str, Dict] = json.load(file) self.ui.log_text_edit.setPlainText(test_results["log"]) del test_results["log"] for test_name in test_results.keys(): sep = test_name.find(':') group, name = test_name[:sep], test_name[sep + 1:] try: self.test_conductor.set_test_results( group, name, test_results[test_name]) except ValueError: logging.warning( f"Тест {group}: {name} не найден! Результаты не восстановлены" ) def clear_results(self): for test in self.tests: test_results = self.test_conductor.get_test_results( test.group(), test.name()) test_results.delete_results() self.tests_widget.set_test_status( test.group(), test.name(), test_results.get_final_status(), test_results.get_success_results_count()) def open_settings(self): try: settings_dialog = SettingsDialog(self.settings, self.netvars_db, self) settings_dialog.exec() except Exception as err: logging.debug(utils.exception_handler(err)) def closeEvent(self, a_event: QtGui.QCloseEvent): if self.calibrator.signal_enable: self.calibrator.signal_enable = False self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS) a_event.ignore() else: self.settings.save_geometry( self.ui.splitter.__class__.__name__ + "1", self.ui.splitter.saveState()) self.settings.save_geometry( self.ui.splitter_2.__class__.__name__ + "2", self.ui.splitter_2.saveState()) self.settings.save_geometry( self.ui.tests_tree.__class__.__name__, self.ui.tests_tree.header().saveState()) self.settings.save_geometry(self.__class__.__name__, self.saveGeometry()) self.tests_widget.save() a_event.accept()
class MainWindow(QtWidgets.QMainWindow): measures_filename = "main_table.csv" default_name_template = "report" MEASURE_TYPE_TO_TEMPLATE_PATH = { UpmsMeasure.MeasureType.MECH_STOPWATCH: ("Templates/ms_template.xlsx", "Templates/ms_template.ods"), UpmsMeasure.MeasureType.ELEC_STOPWATCH: ("Templates/es_template.xlsx", "Templates/es_template.ods"), UpmsMeasure.MeasureType.CLOCK: ("Templates/clock_template.xlsx", "Templates/clock_template.ods"), } def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) try: self.settings = settings.get_ini_settings( os.path.join(self.get_application_path(), "settings.ini")) ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("ini_err")) if ini_ok: self.settings.restore_qwidget_state(self) self.settings.restore_qwidget_state(self.ui.mw_splitter_1) self.settings.restore_qwidget_state(self.ui.measures_table) self.ui.download_progress_bar.setHidden(True) if ENGLISH_VERSION: self.ui.russian_language_action.setVisible(False) self.settings.language = Text.Lang.EN self.translator = QtCore.QTranslator( QtWidgets.QApplication.instance()) self.install_translator(self.settings.language) if self.settings.language == Text.Lang.EN: self.ui.english_language_action.setChecked(True) else: self.ui.russian_language_action.setChecked(True) self.set_up_logger() self.ui.measures_table.setItemDelegate( TransparentPainterForView(self.ui.measures_table, "#d4d4ff")) self.ui.download_path_edit.setText(self.settings.save_folder_path) self.ui.ip_combobox.setEditText(self.settings.ip) self.ui.download_path_edit.setText(self.settings.path) self.ui.name_template_edit.setText(self.settings.name_template) self.ui.save_folder_edit.setText(self.settings.save_folder) self.db = UpmsDatabase( os.path.join(self.get_application_path(), "database.db")) self.measures_table_model = None self.proxy = None self.update_model() self.bcast_sockets = {} self.get_broadcast_ips() self.show() self.connect_all() self.ui.get_ip_button.click() else: self.close() def install_translator(self, a_language: Text.Lang): try: # Для программы, собранной pyinstaller base_path = sys._MEIPASS except AttributeError: base_path = "." translate_file = Text.LANG_TO_QT_TRANSLATE[a_language] self.translator.load(os.path.join(base_path, translate_file)) QtWidgets.QApplication.instance().installTranslator(self.translator) self.ui.retranslateUi(self) Text.set_language(a_language) def connect_all(self): self.ui.open_about_action.triggered.connect(self.open_about) self.ui.download_from_upms_button.clicked.connect( self.download_from_upms_button_clicked) self.ui.ip_combobox.editTextChanged.connect(self.ip_changed) self.ui.download_path_edit.textChanged.connect(self.path_changed) self.ui.name_template_edit.textChanged.connect( self.name_template_changed) self.ui.save_folder_edit.textChanged.connect(self.save_folder_changed) self.ui.get_ip_button.clicked.connect(self.get_ip_button_clicked) self.ui.input_result_button.clicked.connect( self.input_result_button_clicked) self.ui.create_report_button.clicked.connect( self.create_report_button_clicked) self.ui.remove_selected_button.clicked.connect( self.remove_selected_button_clicked) self.ui.choose_download_path_button.clicked.connect( self.choose_download_path_button_clicked) self.ui.choose_save_folder_path_edit.clicked.connect( self.choose_save_folder_path_button_clicked) self.ui.extra_params_button.clicked.connect( self.extra_params_button_clicked) self.ui.russian_language_action.triggered.connect( self.russian_language_chosen) self.ui.english_language_action.triggered.connect( self.english_language_chosen) group = QtWidgets.QActionGroup(self) group.addAction(self.ui.russian_language_action) group.addAction(self.ui.english_language_action) def set_up_logger(self): log = qt_utils.QTextEditLogger(self.ui.log_text_edit) log.setFormatter( logging.Formatter('%(asctime)s - %(message)s', datefmt='%H:%M:%S')) file_log = RotatingFileHandler(os.path.join( self.get_application_path(), "upms_1v_pc.log"), maxBytes=30 * 1024 * 1024, backupCount=3, encoding='utf8') file_log.setLevel(logging.DEBUG) file_log.setFormatter( logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%H:%M:%S')) logging.getLogger().addHandler(file_log) logging.getLogger().addHandler(log) logging.getLogger().setLevel(logging.WARNING) def update_model(self): self.measures_table_model = UpmsDatabaseModel(self.db, self) self.proxy = QtCore.QSortFilterProxyModel() self.proxy.setSourceModel(self.measures_table_model) self.ui.measures_table.setModel(self.proxy) self.ui.measures_table.resizeRowsToContents() def download_measures_list(self, a_download_filepath: str) -> bool: result = False ip = self.ui.ip_combobox.currentText() try: socket.inet_aton(ip) except socket.error: QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("ip_format_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: try: files_list = upms_tftp.get_files_list( self.ui.ip_combobox.currentText()) except ConnectionResetError: QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("connection_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: if files_list is not None: if self.measures_filename in files_list: try: upms_tftp.download_file_by_tftp( ip, self.measures_filename, a_download_filepath) result = True except FileNotFoundError: QtWidgets.QMessageBox.critical( self, Text.get("err"), Text.get("path_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: QtWidgets.QMessageBox.critical( self, Text.get("err"), Text.get("main_table_not_found_err").format( self.measures_filename), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("download_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) return result def download_photo(self, a_measure_id: int, a_files_list: List[str], a_download_folder: str): photo_name = "{}.jpg".format(a_measure_id) download_path = a_download_folder.rstrip(os.sep) + os.sep + photo_name if photo_name in a_files_list: logging.warning("Download {}".format(photo_name)) upms_tftp.download_file_by_tftp(self.ui.ip_combobox.currentText(), photo_name, download_path) @exception_decorator def download_from_upms_button_clicked(self, _): download_folder = self.ui.download_path_edit.text() if download_folder and os.path.isdir(download_folder): download_filepath = download_folder.rstrip( os.sep) + os.sep + self.measures_filename if self.download_measures_list(download_filepath): with open(download_filepath, 'r', encoding='utf8') as measures_list_file: # Первая строка - заголовок measures_list = [ file for idx, file in enumerate(measures_list_file) if idx != 0 ] update_all = False upms_files_list = upms_tftp.get_files_list( self.ui.ip_combobox.currentText()) self.ui.download_progress_bar.setHidden(False) for number, measure in enumerate(measures_list): self.ui.download_progress_bar.setValue( number / (len(upms_files_list) - 1) * self.ui.download_progress_bar.maximum()) measure_params = [ meas.strip() for meas in measure.strip().split(',') ] upms_measure = UpmsMeasure(*measure_params) upms_prev_measure = self.db.get(upms_measure.id) if upms_measure != upms_prev_measure: if upms_prev_measure is None: self.db.add(upms_measure) self.download_photo(upms_measure.id, upms_files_list, download_folder) else: if update_all: res = QtWidgets.QMessageBox.Yes else: res = QtWidgets.QMessageBox.question( self, Text.get("warning"), Text.get("ask_overwrite").format( upms_measure.id), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.YesAll | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Yes) if res == QtWidgets.QMessageBox.Yes: self.db.update(upms_measure) self.download_photo(upms_measure.id, upms_files_list, download_folder) elif res == QtWidgets.QMessageBox.YesAll: self.db.update(upms_measure) self.download_photo(upms_measure.id, upms_files_list, download_folder) update_all = True elif res == QtWidgets.QMessageBox.Cancel: QtWidgets.QMessageBox.warning( self, Text.get("warning"), Text.get("download_canceled"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) break elif not os.path.isfile( os.path.join(download_folder.rstrip(os.sep), "{}.jpg".format(upms_measure.id))): # Докачиваем файл, если запись в БД есть, а файла нет self.download_photo(upms_measure.id, upms_files_list, download_folder) else: QtWidgets.QMessageBox.information( self, Text.get("info"), Text.get("success_download"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) self.ui.download_progress_bar.setValue(0) self.ui.download_progress_bar.setHidden(True) self.update_model() else: QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("path_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) def ip_changed(self, a_ip): self.settings.ip = a_ip def path_changed(self, a_path): self.settings.path = a_path def name_template_changed(self, a_name_template): self.settings.name_template = a_name_template def save_folder_changed(self, a_save_folder): self.settings.save_folder = a_save_folder def get_broadcast_ips(self): localhost = QtNetwork.QHostAddress(QtNetwork.QHostAddress.LocalHost) for _if in QtNetwork.QNetworkInterface.allInterfaces(): for addr in _if.addressEntries(): if addr.ip().protocol() == QtNetwork.QAbstractSocket.IPv4Protocol and not addr.netmask().isNull() and \ addr.ip() != localhost: bcast = QtNetwork.QHostAddress( addr.ip().toIPv4Address() | ((1 << 32) - 1 - addr.netmask().toIPv4Address())) # bit not udp_sock = QtNetwork.QUdpSocket(self) udp_sock.bind(addr.ip()) self.bcast_sockets[bcast.toString()] = udp_sock udp_sock.readyRead.connect(self.read_ip_from_socket) def get_ip_button_clicked(self): for ip, sock in self.bcast_sockets.items(): sock.writeDatagram("upms_1v_get_ip".encode('ascii'), QtNetwork.QHostAddress(ip), 5007) @exception_decorator def read_ip_from_socket(self): self.ui.ip_combobox.clear() for ip, sock in self.bcast_sockets.items(): while sock.hasPendingDatagrams(): datagram = sock.receiveDatagram() data = bytes(datagram.data()).decode(encoding='ascii') ip, _ = data.split(';') try: socket.inet_aton(ip) self.ui.ip_combobox.addItem(ip) except socket.error: logging.error("{} is not valid ip-address".format(ip)) @exception_decorator_print def input_result_button_clicked(self, _): rows = self.ui.measures_table.selectionModel().selectedRows() if rows: for idx in rows: real_row = self.proxy.mapToSource(idx).row() self.ui.measures_table.selectionModel().setCurrentIndex( self.measures_table_model.index(idx.row(), 0), QtCore.QItemSelectionModel.ClearAndSelect | QtCore.QItemSelectionModel.Rows) files_path = self.ui.download_path_edit.text() if files_path and os.path.isdir(files_path): upms_measure = self.measures_table_model.get_upms_measure_by_row( real_row) dialog = ResultInputDialog(upms_measure, files_path, self.settings, self) res = dialog.exec() if res == QtWidgets.QDialog.Accepted: new_result = dialog.get_result() self.measures_table_model.update_result( real_row, new_result) logging.warning(upms_measure.result) # Для сохранения состояния (иначе не вызывается closeEvent) dialog.close() else: break else: QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("path_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: QtWidgets.QMessageBox.information(self, Text.get("info"), Text.get("selection_info"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) # def get_template_file(self, a_measure_type) -> str: # for path in self.MEASURE_TYPE_TO_TEMPLATE_PATH[a_measure_type]: # if os.path.isfile(path): # return path # return "" @staticmethod def get_accessible_name(a_name_template, a_save_folder, a_extension: str) -> str: number = 2 name = a_name_template while os.path.isfile("{}{}{}{}".format(a_save_folder.rstrip(os.sep), os.sep, name, a_extension)): name = "{}_{}".format(a_name_template, number) number += 1 return "{}{}".format(name, a_extension) @staticmethod def get_application_path(): if getattr(sys, 'frozen', False): application_path = os.path.dirname(sys.executable) else: application_path = os.path.dirname(__file__) return application_path def create_protocol_generator( self, a_name_template, a_save_folder, a_measure_type, a_generator: Type[pg.UpmsProtocolGenerator] ) -> Optional[pg.UpmsProtocolGenerator]: extension = a_generator.protocol_ext() template_files = \ list(filter(lambda s: s.endswith(extension), self.MEASURE_TYPE_TO_TEMPLATE_PATH[a_measure_type])) template_filename = os.path.join(self.get_application_path(), template_files[0]) if os.path.isfile(template_filename): filename = self.get_accessible_name(a_name_template, a_save_folder, extension) report_path = os.path.join(a_save_folder.rstrip(os.sep), filename) shutil.copyfile(template_filename, report_path) return a_generator(report_path) else: QtWidgets.QMessageBox.critical( self, Text.get("err"), Text.get("templates_are_not_found").format(template_filename), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) return None @exception_decorator def create_report(self, a_name_template, a_save_folder, a_measure_type: UpmsMeasure.MeasureType, a_photos_path, a_upms_measures: List[UpmsMeasure]): protocol_generators = [] if True: generator = self.create_protocol_generator( a_name_template, a_save_folder, a_measure_type, pg.ExcelProtocolGenerator) if generator is not None: protocol_generators.append(generator) if False: generator = self.create_protocol_generator( a_name_template, a_save_folder, a_measure_type, pg.CalcProtocolGenerator) if generator is not None: protocol_generators.append(generator) for protocol_gen in protocol_generators: if protocol_gen.is_template_ok(): protocol_gen.insert_measures(a_upms_measures) protocol_gen.insert_extra_parameters(self.db.get_parameters()) protocol_gen.insert_photos(a_photos_path, a_upms_measures) protocol_gen.save() QtWidgets.QMessageBox.information( self, Text.get("info"), Text.get("success_generated").format( protocol_gen.get_report_path()), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) if os.name == 'nt': os.startfile(protocol_gen.get_report_path()) else: opener = "open" if sys.platform == "darwin" else "xdg-open" subprocess.call([opener, protocol_gen.get_report_path()]) else: QtWidgets.QMessageBox.critical( self, Text.get("err"), Text.get("data_sheet_not_found").format( protocol_gen.get_report_path()), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) @exception_decorator def create_report_button_clicked(self, _): rows = self.ui.measures_table.selectionModel().selectedRows() if rows: types = [ self.measures_table_model.get_type( self.proxy.mapToSource(idx).row()) for idx in rows ] if len(types) == types.count(types[0]): save_folder = self.ui.save_folder_edit.text() if save_folder and os.path.isdir(save_folder): if self.ui.download_path_edit.text(): name_template = self.ui.name_template_edit.text() if self.ui.name_template_edit.text() else \ self.default_name_template upms_measures = [ self.measures_table_model.get_upms_measure_by_row( self.proxy.mapToSource(idx).row()) for idx in rows ] self.create_report(name_template, save_folder, types[0], self.ui.download_path_edit.text(), upms_measures) else: QtWidgets.QMessageBox.critical( self, Text.get("err"), Text.get("path_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: QtWidgets.QMessageBox.critical( self, Text.get("err"), Text.get("save_folder_error"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: QtWidgets.QMessageBox.critical(self, Text.get("err"), Text.get("same_type_err"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) else: QtWidgets.QMessageBox.information(self, Text.get("info"), Text.get("selection_info"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) def remove_selected_button_clicked(self, _): rows = self.ui.measures_table.selectionModel().selectedRows() if rows: res = QtWidgets.QMessageBox.question( self, Text.get("confirm"), Text.get("delete_confirm"), QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel) if res == QtWidgets.QMessageBox.Ok: real_rows = [self.proxy.mapToSource(r).row() for r in rows] real_rows.sort(reverse=True) for row in real_rows: self.measures_table_model.remove_row(row) else: QtWidgets.QMessageBox.information(self, Text.get("info"), Text.get("selection_info"), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) def extra_params_button_clicked(self, _): old_parameters = self.db.get_parameters() dialog = ExtraParametersDialog(old_parameters, self.settings) res = dialog.exec() if res == QtWidgets.QDialog.Accepted: new_parameters = dialog.get_parameters() self.db.set_parameters(new_parameters) dialog.close() def choose_download_path_button_clicked(self): new_path = QtWidgets.QFileDialog.getExistingDirectory( self, Text.get("download_folder"), self.settings.path) if new_path: self.ui.download_path_edit.setText(new_path) def choose_save_folder_path_button_clicked(self): new_path = QtWidgets.QFileDialog.getExistingDirectory( self, Text.get("save_folder"), self.settings.save_folder) if new_path: self.ui.save_folder_edit.setText(new_path) def russian_language_chosen(self): self.install_translator(Text.Lang.RU) self.settings.language = int(Text.Lang.RU) def english_language_chosen(self): self.install_translator(Text.Lang.EN) self.settings.language = int(Text.Lang.EN) def open_about(self): about_dialog = AboutDialog(self) about_dialog.exec() def closeEvent(self, a_event: QtGui.QCloseEvent): self.settings.save_qwidget_state(self.ui.measures_table) self.settings.save_qwidget_state(self.ui.mw_splitter_1) self.settings.save_qwidget_state(self) a_event.accept()
class MainWindow(QtWidgets.QMainWindow): clb_list_changed = QtCore.pyqtSignal([list]) usb_status_changed = QtCore.pyqtSignal(clb.State) signal_enable_changed = QtCore.pyqtSignal(bool) def __init__(self): super().__init__() self.ui = MainForm() self.ui.setupUi(self) self.active_window = None try: self.settings = Settings(self) ini_ok = True except BadIniException: ini_ok = False QtWidgets.QMessageBox.critical( self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, ' 'удалите файл "settings.ini" и запустите программу заново') if ini_ok: self.db_name = "measures.db" self.db_connection = MeasuresDB.create_db(self.db_name) self.show_start_window() self.show() self.clb_signal_off_timer = QtCore.QTimer() # noinspection PyTypeChecker self.clb_signal_off_timer.timeout.connect(self.close) self.SIGNAL_OFF_TIME_MS = 200 self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path) self.usb_driver = clb_dll.UsbDrv(self.clb_driver) self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED self.calibrator = clb_dll.ClbDrv(self.clb_driver) self.clb_state = clb.State.DISCONNECTED self.usb_check_timer = QtCore.QTimer(self) self.usb_check_timer.timeout.connect(self.usb_tick) self.usb_check_timer.start(10) self.fast_config = None self.ui.enter_settings_action.triggered.connect(self.open_settings) else: self.close() def __del__(self): if hasattr(self, "display_db_connection"): self.db_connection.close() def usb_tick(self): self.usb_driver.tick() if self.usb_driver.is_dev_list_changed(): self.clb_list_changed.emit(self.usb_driver.get_dev_list()) if self.usb_driver.is_status_changed(): self.usb_state = self.usb_driver.get_status() current_state = clb.State.DISCONNECTED if self.usb_state == clb_dll.UsbDrv.UsbState.CONNECTED: if self.calibrator.signal_enable_changed(): self.signal_enable_changed.emit(self.calibrator.signal_enable) if not self.calibrator.signal_enable: current_state = clb.State.STOPPED elif not self.calibrator.is_signal_ready(): current_state = clb.State.WAITING_SIGNAL else: current_state = clb.State.READY if self.clb_state != current_state: self.clb_state = current_state self.usb_status_changed.emit(self.clb_state) def close_active_window(self): self.hide() if self.active_window is not None: self.active_window.close() def show_start_window(self): try: self.close_active_window() self.active_window = StartWindow(self.db_connection, self.db_name, self.settings, self) self.setCentralWidget(self.active_window) self.active_window.source_mode_chosen.connect( self.open_source_mode_window) self.active_window.no_template_mode_chosen.connect( self.open_config_no_template_mode) self.active_window.template_mode_chosen.connect( self.template_mode_chosen) self.setWindowTitle(self.active_window.windowTitle()) except Exception as err: utils.exception_handler(err) def attach_calibrator_to_window(self, a_window): assert hasattr(a_window, "update_clb_list"), "no method update_clb_list" assert hasattr(a_window, "update_clb_status"), "no method update_clb_status" self.clb_list_changed.connect(a_window.update_clb_list) self.clb_list_changed.emit(self.usb_driver.get_dev_list()) self.usb_status_changed.connect(a_window.update_clb_status) self.usb_status_changed.emit(self.clb_state) self.signal_enable_changed.connect(a_window.signal_enable_changed) self.signal_enable_changed.emit(self.calibrator.signal_enable) def change_window(self, a_new_window): self.active_window = a_new_window self.attach_calibrator_to_window(self.active_window) self.setCentralWidget(self.active_window) self.setWindowTitle(self.active_window.windowTitle()) self.active_window.close_confirmed.connect(self.close_child_widget) def open_source_mode_window(self): try: source_mode_dialog = SourceModeDialog(self.settings, self.calibrator, self) self.attach_calibrator_to_window(source_mode_dialog) source_mode_dialog.exec() except Exception as err: utils.exception_handler(err) def open_config_no_template_mode(self): try: new_fast_measure_window = NewFastMeasureDialog( self.fast_config, self) new_fast_measure_window.config_ready.connect( self.save_no_template_config) if new_fast_measure_window.exec() == QtWidgets.QDialog.Accepted: assert self.fast_config is not None, "no_template_config must not be None!" new_fast_measure_window.close() self.start_fast_measure() except AssertionError as err: print(err) def save_no_template_config(self, a_config: FastMeasureParams): self.fast_config = a_config def start_fast_measure(self): try: measure_config = Measure.from_fast_params(self.fast_config) self.close_active_window() self.change_window( MeasureWindow(a_calibrator=self.calibrator, a_measure_config=measure_config, a_db_connection=self.db_connection, a_settings=self.settings, a_parent=self)) except Exception as err: utils.exception_handler(err) def template_mode_chosen(self): try: template_list_dialog = TemplateListWindow(self.settings, self) template_list_dialog.config_ready.connect( self.start_template_measure) template_list_dialog.exec() except Exception as err: utils.exception_handler(err) def start_template_measure(self, a_template_params: TemplateParams, a_variable_params: VariableTemplateParams): try: measure_config = Measure.from_template(a_template_params, a_variable_params) self.close_active_window() self.change_window( MeasureWindow(a_calibrator=self.calibrator, a_measure_config=measure_config, a_db_connection=self.db_connection, a_settings=self.settings, a_parent=self)) except Exception as err: utils.exception_handler(err) def close_child_widget(self): self.show_start_window() def open_settings(self): try: settings_dialog = SettingsDialog(self.settings, self.db_connection, self) settings_dialog.exec() except Exception as err: utils.exception_handler(err) def closeEvent(self, a_event: QtGui.QCloseEvent): try: if not isinstance(self.active_window, StartWindow): if hasattr(self.active_window, "ask_for_close"): # Эмитит close_confirmed при подтверждении закрытия self.active_window.ask_for_close() a_event.ignore() else: a_event.accept() else: if self.calibrator.signal_enable: self.calibrator.signal_enable = False self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS) a_event.ignore() else: self.active_window.close() a_event.accept() except Exception as err: print(err)