Add advanced TerminalWidget with enhanced text display and formatting
- Implement TerminalWidget class with color-coded message types - Add support for error, warning, info, and command message styles - Include automatic scrollbar and text formatting - Replace CustomText with TerminalWidget in interactive tabs - Enhance text appending methods with type-specific display - Improve terminal readability with command separators
This commit is contained in:
138
ComConfigCopy.py
138
ComConfigCopy.py
@@ -670,6 +670,86 @@ def send_command_and_process_response(
|
|||||||
logging.error(msg)
|
logging.error(msg)
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
# Класс для терминального виджета с расширенной функциональностью
|
||||||
|
class TerminalWidget(CustomText):
|
||||||
|
def __init__(self, master, *args, **kwargs):
|
||||||
|
super().__init__(master, *args, **kwargs)
|
||||||
|
|
||||||
|
# Настройка цветов для разных типов сообщений
|
||||||
|
self.tag_configure("error", foreground="red")
|
||||||
|
self.tag_configure("warning", foreground="orange")
|
||||||
|
self.tag_configure("info", foreground="blue")
|
||||||
|
self.tag_configure("command", foreground="green")
|
||||||
|
self.tag_configure("separator", foreground="gray")
|
||||||
|
|
||||||
|
# Добавляем скроллбар
|
||||||
|
self.scrollbar = ttk.Scrollbar(self, command=self.yview)
|
||||||
|
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
self.config(yscrollcommand=self.scrollbar.set)
|
||||||
|
|
||||||
|
# Настройка отступов и переносов
|
||||||
|
self.config(
|
||||||
|
wrap=tk.WORD,
|
||||||
|
padx=5,
|
||||||
|
pady=5,
|
||||||
|
spacing1=2, # Отступ перед абзацем
|
||||||
|
spacing2=2, # Межстрочный интервал
|
||||||
|
spacing3=2 # Отступ после абзаца
|
||||||
|
)
|
||||||
|
|
||||||
|
# Счетчик команд для разделителей
|
||||||
|
self.command_counter = 0
|
||||||
|
|
||||||
|
def append_text(self, text, message_type=None):
|
||||||
|
"""
|
||||||
|
Добавление текста с определенным типом сообщения
|
||||||
|
message_type может быть: 'error', 'warning', 'info', 'command'
|
||||||
|
"""
|
||||||
|
# Добавляем разделитель между командами
|
||||||
|
if message_type == "command":
|
||||||
|
if self.command_counter > 0:
|
||||||
|
self.insert(tk.END, "\n" + "─" * 80 + "\n", "separator")
|
||||||
|
self.command_counter += 1
|
||||||
|
|
||||||
|
# Добавляем текст
|
||||||
|
if not text.endswith('\n'):
|
||||||
|
text += '\n'
|
||||||
|
|
||||||
|
start_index = self.index(tk.END)
|
||||||
|
self.insert(tk.END, text)
|
||||||
|
end_index = self.index(tk.END)
|
||||||
|
|
||||||
|
# Применяем тег в зависимости от типа сообщения
|
||||||
|
if message_type:
|
||||||
|
self.tag_add(message_type, start_index, end_index)
|
||||||
|
|
||||||
|
# Автоматическая прокрутка к концу
|
||||||
|
self.see(tk.END)
|
||||||
|
|
||||||
|
# Обновляем виджет
|
||||||
|
self.update_idletasks()
|
||||||
|
|
||||||
|
def append_error(self, text):
|
||||||
|
"""Добавление сообщения об ошибке"""
|
||||||
|
self.append_text(text, "error")
|
||||||
|
|
||||||
|
def append_warning(self, text):
|
||||||
|
"""Добавление предупреждения"""
|
||||||
|
self.append_text(text, "warning")
|
||||||
|
|
||||||
|
def append_info(self, text):
|
||||||
|
"""Добавление информационного сообщения"""
|
||||||
|
self.append_text(text, "info")
|
||||||
|
|
||||||
|
def append_command(self, text):
|
||||||
|
"""Добавление команды"""
|
||||||
|
self.append_text(text, "command")
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Очистка терминала"""
|
||||||
|
self.delete("1.0", tk.END)
|
||||||
|
self.command_counter = 0
|
||||||
|
|
||||||
# Основной класс для графического интерфейса
|
# Основной класс для графического интерфейса
|
||||||
class SerialAppGUI(tk.Tk):
|
class SerialAppGUI(tk.Tk):
|
||||||
def __init__(self, settings):
|
def __init__(self, settings):
|
||||||
@@ -849,7 +929,8 @@ class SerialAppGUI(tk.Tk):
|
|||||||
)
|
)
|
||||||
disconnect_btn.pack(side=LEFT, padx=5)
|
disconnect_btn.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
self.interactive_text = CustomText(frame, wrap="word", height=20)
|
# Используем новый TerminalWidget вместо CustomText
|
||||||
|
self.interactive_text = TerminalWidget(frame, height=20)
|
||||||
self.interactive_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
self.interactive_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
input_frame = ttk.Frame(frame)
|
input_frame = ttk.Frame(frame)
|
||||||
@@ -876,10 +957,10 @@ class SerialAppGUI(tk.Tk):
|
|||||||
return
|
return
|
||||||
self.connection = create_connection(self.settings)
|
self.connection = create_connection(self.settings)
|
||||||
if self.connection:
|
if self.connection:
|
||||||
self.append_interactive_text("[INFO] Подключение установлено.\n")
|
self.interactive_text.append_info("[INFO] Подключение установлено.")
|
||||||
self.update_status_bar() # Обновляем статус бар
|
self.update_status_bar() # Обновляем статус бар
|
||||||
else:
|
else:
|
||||||
self.append_interactive_text("[ERROR] Не удалось установить соединение.\n")
|
self.interactive_text.append_error("[ERROR] Не удалось установить соединение.")
|
||||||
|
|
||||||
# Отключение от устройства
|
# Отключение от устройства
|
||||||
def disconnect_device(self):
|
def disconnect_device(self):
|
||||||
@@ -889,7 +970,7 @@ class SerialAppGUI(tk.Tk):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.connection = None
|
self.connection = None
|
||||||
self.append_interactive_text("[INFO] Соединение закрыто.\n")
|
self.interactive_text.append_info("[INFO] Соединение закрыто.")
|
||||||
self.update_status_bar() # Обновляем статус бар
|
self.update_status_bar() # Обновляем статус бар
|
||||||
else:
|
else:
|
||||||
messagebox.showinfo("Информация", "Соединение не установлено.")
|
messagebox.showinfo("Информация", "Соединение не установлено.")
|
||||||
@@ -902,7 +983,7 @@ class SerialAppGUI(tk.Tk):
|
|||||||
cmd = self.command_entry.get().strip()
|
cmd = self.command_entry.get().strip()
|
||||||
if not cmd:
|
if not cmd:
|
||||||
return
|
return
|
||||||
self.append_interactive_text(f"[INFO] Отправка команды: {cmd}\n")
|
self.interactive_text.append_command(f"[CMD] {cmd}")
|
||||||
threading.Thread(target=self.process_command, args=(cmd,), daemon=True).start()
|
threading.Thread(target=self.process_command, args=(cmd,), daemon=True).start()
|
||||||
|
|
||||||
# Обработка команды
|
# Обработка команды
|
||||||
@@ -919,15 +1000,22 @@ class SerialAppGUI(tk.Tk):
|
|||||||
is_gui=True
|
is_gui=True
|
||||||
)
|
)
|
||||||
except SerialException as e:
|
except SerialException as e:
|
||||||
self.append_interactive_text(f"[ERROR] Ошибка при отправке команды: {e}\n")
|
self.interactive_text.append_error(f"[ERROR] Ошибка при отправке команды: {e}")
|
||||||
logging.error(f"Ошибка отправки команды: {e}", exc_info=True)
|
logging.error(f"Ошибка отправки команды: {e}", exc_info=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.append_interactive_text(f"[ERROR] Неизвестная ошибка: {e}\n")
|
self.interactive_text.append_error(f"[ERROR] Неизвестная ошибка: {e}")
|
||||||
logging.error(f"Неизвестная ошибка: {e}", exc_info=True)
|
logging.error(f"Неизвестная ошибка: {e}", exc_info=True)
|
||||||
|
|
||||||
# Добавление текста в текстовое поле
|
# Добавление текста в текстовое поле
|
||||||
def append_interactive_text(self, text):
|
def append_interactive_text(self, text):
|
||||||
append_text_to_widget(self.interactive_text, text)
|
if "[ERROR]" in text:
|
||||||
|
self.interactive_text.append_error(text)
|
||||||
|
elif "[WARNING]" in text or "[WARN]" in text:
|
||||||
|
self.interactive_text.append_warning(text)
|
||||||
|
elif "[INFO]" in text:
|
||||||
|
self.interactive_text.append_info(text)
|
||||||
|
else:
|
||||||
|
self.interactive_text.append_text(text)
|
||||||
|
|
||||||
# Создание вкладки "Выполнить команды из файла"
|
# Создание вкладки "Выполнить команды из файла"
|
||||||
def create_file_exec_tab(self, frame):
|
def create_file_exec_tab(self, frame):
|
||||||
@@ -938,9 +1026,21 @@ class SerialAppGUI(tk.Tk):
|
|||||||
CustomEntry(file_frame, textvariable=self.file_exec_var, width=40).pack(side=LEFT, padx=5)
|
CustomEntry(file_frame, textvariable=self.file_exec_var, width=40).pack(side=LEFT, padx=5)
|
||||||
ttk.Button(file_frame, text="Выбрать", command=self.select_config_file_fileexec).pack(side=LEFT, padx=5)
|
ttk.Button(file_frame, text="Выбрать", command=self.select_config_file_fileexec).pack(side=LEFT, padx=5)
|
||||||
ttk.Button(frame, text="Выполнить команды", command=self.execute_file_commands).pack(pady=5)
|
ttk.Button(frame, text="Выполнить команды", command=self.execute_file_commands).pack(pady=5)
|
||||||
self.file_exec_text = CustomText(frame, wrap="word", height=15)
|
|
||||||
|
# Используем новый TerminalWidget вместо CustomText
|
||||||
|
self.file_exec_text = TerminalWidget(frame, height=15)
|
||||||
self.file_exec_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
self.file_exec_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
|
def append_file_exec_text(self, text):
|
||||||
|
if "[ERROR]" in text:
|
||||||
|
self.file_exec_text.append_error(text)
|
||||||
|
elif "[WARNING]" in text or "[WARN]" in text:
|
||||||
|
self.file_exec_text.append_warning(text)
|
||||||
|
elif "[INFO]" in text:
|
||||||
|
self.file_exec_text.append_info(text)
|
||||||
|
else:
|
||||||
|
self.file_exec_text.append_text(text)
|
||||||
|
|
||||||
# Выбор файла конфигурации для выполнения команд
|
# Выбор файла конфигурации для выполнения команд
|
||||||
def select_config_file_fileexec(self):
|
def select_config_file_fileexec(self):
|
||||||
select_config_file(self, self.file_exec_var)
|
select_config_file(self, self.file_exec_var)
|
||||||
@@ -974,9 +1074,6 @@ class SerialAppGUI(tk.Tk):
|
|||||||
daemon=True,
|
daemon=True,
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
def append_file_exec_text(self, text):
|
|
||||||
append_text_to_widget(self.file_exec_text, text)
|
|
||||||
|
|
||||||
# Создание вкладки "Редактор конфигурационного файла"
|
# Создание вкладки "Редактор конфигурационного файла"
|
||||||
def create_config_editor_tab(self, frame):
|
def create_config_editor_tab(self, frame):
|
||||||
top_frame = ttk.Frame(frame)
|
top_frame = ttk.Frame(frame)
|
||||||
@@ -1084,13 +1181,9 @@ class SerialAppGUI(tk.Tk):
|
|||||||
log_frame = ttk.LabelFrame(tftp_frame, text="Лог сервера")
|
log_frame = ttk.LabelFrame(tftp_frame, text="Лог сервера")
|
||||||
log_frame.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
log_frame.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
self.tftp_log_text = CustomText(log_frame, wrap=tk.WORD, height=10)
|
# Используем новый TerminalWidget вместо CustomText
|
||||||
|
self.tftp_log_text = TerminalWidget(log_frame, height=10)
|
||||||
self.tftp_log_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
self.tftp_log_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
# Добавляем скроллбар для лога
|
|
||||||
scrollbar = ttk.Scrollbar(self.tftp_log_text, command=self.tftp_log_text.yview)
|
|
||||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
||||||
self.tftp_log_text.config(yscrollcommand=scrollbar.set)
|
|
||||||
|
|
||||||
# Статус передач
|
# Статус передач
|
||||||
transfers_frame = ttk.LabelFrame(tftp_frame, text="Активные передачи")
|
transfers_frame = ttk.LabelFrame(tftp_frame, text="Активные передачи")
|
||||||
@@ -1242,7 +1335,14 @@ class SerialAppGUI(tk.Tk):
|
|||||||
self.stop_tftp_button.config(state="normal")
|
self.stop_tftp_button.config(state="normal")
|
||||||
|
|
||||||
def append_tftp_log(self, text):
|
def append_tftp_log(self, text):
|
||||||
append_text_to_widget(self.tftp_log_text, text)
|
if "[ERROR]" in text:
|
||||||
|
self.tftp_log_text.append_error(text)
|
||||||
|
elif "[WARNING]" in text or "[WARN]" in text:
|
||||||
|
self.tftp_log_text.append_warning(text)
|
||||||
|
elif "[INFO]" in text:
|
||||||
|
self.tftp_log_text.append_info(text)
|
||||||
|
else:
|
||||||
|
self.tftp_log_text.append_text(text)
|
||||||
|
|
||||||
# Обновление информации об активных передачах
|
# Обновление информации об активных передачах
|
||||||
def update_transfers_info(self):
|
def update_transfers_info(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user