Enhance terminal widgets with read-only mode and clear functionality
- Add read-only mode to TerminalWidget to prevent manual text editing - Disable text paste and key input in terminal widgets - Modify context menu to remove cut and paste options - Add clear buttons for interactive, file execution, and TFTP log terminals - Implement temporary state changes for text appending and clearing
This commit is contained in:
@@ -695,17 +695,33 @@ class TerminalWidget(CustomText):
|
|||||||
pady=5,
|
pady=5,
|
||||||
spacing1=2, # Отступ перед абзацем
|
spacing1=2, # Отступ перед абзацем
|
||||||
spacing2=2, # Межстрочный интервал
|
spacing2=2, # Межстрочный интервал
|
||||||
spacing3=2 # Отступ после абзаца
|
spacing3=2, # Отступ после абзаца
|
||||||
|
state='disabled' # Делаем виджет только для чтения
|
||||||
)
|
)
|
||||||
|
|
||||||
# Счетчик команд для разделителей
|
# Счетчик команд для разделителей
|
||||||
self.command_counter = 0
|
self.command_counter = 0
|
||||||
|
|
||||||
|
# Отключаем возможность вставки текста
|
||||||
|
self.bind('<<Paste>>', lambda e: 'break')
|
||||||
|
self.bind('<Key>', self._readonly)
|
||||||
|
|
||||||
|
# Изменяем контекстное меню
|
||||||
|
self.context_menu.delete("Вырезать")
|
||||||
|
self.context_menu.delete("Вставить")
|
||||||
|
|
||||||
|
def _readonly(self, event):
|
||||||
|
"""Обработчик для блокировки ввода"""
|
||||||
|
return 'break'
|
||||||
|
|
||||||
def append_text(self, text, message_type=None):
|
def append_text(self, text, message_type=None):
|
||||||
"""
|
"""
|
||||||
Добавление текста с определенным типом сообщения
|
Добавление текста с определенным типом сообщения
|
||||||
message_type может быть: 'error', 'warning', 'info', 'command'
|
message_type может быть: 'error', 'warning', 'info', 'command'
|
||||||
"""
|
"""
|
||||||
|
# Временно разрешаем изменение для добавления текста
|
||||||
|
self.config(state='normal')
|
||||||
|
|
||||||
# Добавляем текст
|
# Добавляем текст
|
||||||
if not text.endswith('\n'):
|
if not text.endswith('\n'):
|
||||||
text += '\n'
|
text += '\n'
|
||||||
@@ -721,6 +737,9 @@ class TerminalWidget(CustomText):
|
|||||||
# Автоматическая прокрутка к концу
|
# Автоматическая прокрутка к концу
|
||||||
self.see(tk.END)
|
self.see(tk.END)
|
||||||
|
|
||||||
|
# Возвращаем состояние "только для чтения"
|
||||||
|
self.config(state='disabled')
|
||||||
|
|
||||||
# Обновляем виджет
|
# Обновляем виджет
|
||||||
self.update_idletasks()
|
self.update_idletasks()
|
||||||
|
|
||||||
@@ -738,6 +757,9 @@ class TerminalWidget(CustomText):
|
|||||||
|
|
||||||
def append_command(self, text):
|
def append_command(self, text):
|
||||||
"""Добавление команды с разделителем"""
|
"""Добавление команды с разделителем"""
|
||||||
|
# Временно разрешаем изменение для добавления текста
|
||||||
|
self.config(state='normal')
|
||||||
|
|
||||||
# Добавляем разделитель между командами
|
# Добавляем разделитель между командами
|
||||||
if self.command_counter > 0:
|
if self.command_counter > 0:
|
||||||
self.insert(tk.END, "\n" + "─" * 80 + "\n", "separator")
|
self.insert(tk.END, "\n" + "─" * 80 + "\n", "separator")
|
||||||
@@ -746,9 +768,14 @@ class TerminalWidget(CustomText):
|
|||||||
# Добавляем команду
|
# Добавляем команду
|
||||||
self.append_text(text, "command")
|
self.append_text(text, "command")
|
||||||
|
|
||||||
|
# Возвращаем состояние "только для чтения"
|
||||||
|
self.config(state='disabled')
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
"""Очистка терминала"""
|
"""Очистка терминала"""
|
||||||
|
self.config(state='normal')
|
||||||
self.delete("1.0", tk.END)
|
self.delete("1.0", tk.END)
|
||||||
|
self.config(state='disabled')
|
||||||
self.command_counter = 0
|
self.command_counter = 0
|
||||||
|
|
||||||
# Основной класс для графического интерфейса
|
# Основной класс для графического интерфейса
|
||||||
@@ -944,6 +971,14 @@ class SerialAppGUI(tk.Tk):
|
|||||||
)
|
)
|
||||||
disconnect_btn.pack(side=LEFT, padx=5)
|
disconnect_btn.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
|
# Кнопка очистки терминала
|
||||||
|
clear_btn = ttk.Button(
|
||||||
|
control_frame,
|
||||||
|
text="🗑 Очистить", # Unicode символ для "корзины"
|
||||||
|
command=lambda: self.interactive_text.clear()
|
||||||
|
)
|
||||||
|
clear_btn.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
# Используем новый TerminalWidget вместо CustomText
|
# Используем новый TerminalWidget вместо CustomText
|
||||||
self.interactive_text = TerminalWidget(frame, height=20)
|
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)
|
||||||
@@ -1107,6 +1142,10 @@ class SerialAppGUI(tk.Tk):
|
|||||||
self.stop_button = ttk.Button(control_frame, text="⏹ Остановить", command=self.stop_execution, state="disabled")
|
self.stop_button = ttk.Button(control_frame, text="⏹ Остановить", command=self.stop_execution, state="disabled")
|
||||||
self.stop_button.pack(side=LEFT, padx=5)
|
self.stop_button.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
|
# Кнопка очистки терминала
|
||||||
|
self.clear_button = ttk.Button(control_frame, text="🗑 Очистить", command=lambda: self.file_exec_text.clear())
|
||||||
|
self.clear_button.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
# Создаем фрейм для индикатора прогресса и таймера
|
# Создаем фрейм для индикатора прогресса и таймера
|
||||||
progress_frame = ttk.Frame(frame)
|
progress_frame = ttk.Frame(frame)
|
||||||
progress_frame.pack(fill=X, pady=5, padx=5)
|
progress_frame.pack(fill=X, pady=5, padx=5)
|
||||||
@@ -1197,12 +1236,22 @@ class SerialAppGUI(tk.Tk):
|
|||||||
|
|
||||||
def check_connection():
|
def check_connection():
|
||||||
"""Проверка состояния соединения"""
|
"""Проверка состояния соединения"""
|
||||||
|
# Если выполнение остановлено пользователем, просто возвращаем False без сообщений
|
||||||
|
if self.execution_stop:
|
||||||
|
return False
|
||||||
|
|
||||||
if not self.connection or not self.connection.is_open:
|
if not self.connection or not self.connection.is_open:
|
||||||
|
# Если остановка произошла во время проверки, не показываем сообщение
|
||||||
|
if self.execution_stop:
|
||||||
|
return False
|
||||||
|
|
||||||
self.append_file_exec_text("[ERROR] Соединение потеряно!\n")
|
self.append_file_exec_text("[ERROR] Соединение потеряно!\n")
|
||||||
# Автоматически ставим на паузу
|
# Автоматически ставим на паузу
|
||||||
self.execution_paused = True
|
self.execution_paused = True
|
||||||
self.after(0, lambda: self.pause_button.config(text="▶ Продолжить"))
|
self.after(0, lambda: self.pause_button.config(text="▶ Продолжить"))
|
||||||
# Показываем сообщение пользователю
|
|
||||||
|
# Показываем сообщение только если это не ручная остановка
|
||||||
|
if not self.execution_stop:
|
||||||
self.after(0, lambda: messagebox.showerror(
|
self.after(0, lambda: messagebox.showerror(
|
||||||
"Ошибка соединения",
|
"Ошибка соединения",
|
||||||
"Соединение с устройством потеряно!\nВыполнение команд приостановлено.\n\n"
|
"Соединение с устройством потеряно!\nВыполнение команд приостановлено.\n\n"
|
||||||
@@ -1583,6 +1632,14 @@ class SerialAppGUI(tk.Tk):
|
|||||||
)
|
)
|
||||||
self.stop_tftp_button.pack(side=LEFT, padx=5)
|
self.stop_tftp_button.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
|
# Кнопка очистки лога
|
||||||
|
self.clear_tftp_button = ttk.Button(
|
||||||
|
buttons_frame,
|
||||||
|
text="🗑 Очистить лог",
|
||||||
|
command=lambda: self.tftp_log_text.clear()
|
||||||
|
)
|
||||||
|
self.clear_tftp_button.pack(side=LEFT, padx=5)
|
||||||
|
|
||||||
# Лог сервера
|
# Лог сервера
|
||||||
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user