Add custom text and entry widgets with enhanced copy/paste functionality
- Implement CustomText and CustomEntry classes with advanced text interaction features - Add context menu for text widgets with cut, copy, paste, and select all options - Support multiple keyboard shortcuts for text manipulation - Replace standard Tkinter Text and Entry widgets with custom implementations - Remove global text/entry widget bindings in favor of class-specific methods
This commit is contained in:
130
ComConfigCopy.py
130
ComConfigCopy.py
@@ -437,9 +437,109 @@ def execute_commands_from_file(
|
||||
logging.error(f"Ошибка при выполнении команд из файла: {e}", exc_info=True)
|
||||
|
||||
# ==========================
|
||||
# Графический интерфейс (Tkinter)
|
||||
# Улучшенные текстовые виджеты
|
||||
# ==========================
|
||||
|
||||
class CustomText(tk.Text):
|
||||
"""Улучшенный текстовый виджет с расширенной функциональностью копирования/вставки"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.create_context_menu()
|
||||
self.bind_shortcuts()
|
||||
|
||||
def create_context_menu(self):
|
||||
self.context_menu = tk.Menu(self, tearoff=0)
|
||||
self.context_menu.add_command(label="Вырезать", command=self.cut)
|
||||
self.context_menu.add_command(label="Копировать", command=self.copy)
|
||||
self.context_menu.add_command(label="Вставить", command=self.paste)
|
||||
self.context_menu.add_separator()
|
||||
self.context_menu.add_command(label="Выделить всё", command=self.select_all)
|
||||
|
||||
self.bind("<Button-3>", self.show_context_menu)
|
||||
|
||||
def show_context_menu(self, event):
|
||||
self.context_menu.post(event.x_root, event.y_root)
|
||||
|
||||
def bind_shortcuts(self):
|
||||
# Стандартные сочетания
|
||||
self.bind("<Control-x>", lambda e: self.event_generate("<<Cut>>"))
|
||||
self.bind("<Control-c>", lambda e: self.event_generate("<<Copy>>"))
|
||||
self.bind("<Control-v>", lambda e: self.event_generate("<<Paste>>"))
|
||||
self.bind("<Control-a>", self.select_all)
|
||||
|
||||
# Shift+Insert для вставки
|
||||
self.bind("<Shift-Insert>", lambda e: self.event_generate("<<Paste>>"))
|
||||
|
||||
# Ctrl+Insert для копирования
|
||||
self.bind("<Control-Insert>", lambda e: self.event_generate("<<Copy>>"))
|
||||
|
||||
# Shift+Delete для вырезания
|
||||
self.bind("<Shift-Delete>", lambda e: self.event_generate("<<Cut>>"))
|
||||
|
||||
def cut(self):
|
||||
self.event_generate("<<Cut>>")
|
||||
|
||||
def copy(self):
|
||||
self.event_generate("<<Copy>>")
|
||||
|
||||
def paste(self):
|
||||
self.event_generate("<<Paste>>")
|
||||
|
||||
def select_all(self, event=None):
|
||||
self.tag_add(tk.SEL, "1.0", tk.END)
|
||||
self.mark_set(tk.INSERT, "1.0")
|
||||
self.see(tk.INSERT)
|
||||
return "break"
|
||||
|
||||
class CustomEntry(ttk.Entry):
|
||||
"""Улучшенное поле ввода с расширенной функциональностью копирования/вставки"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.create_context_menu()
|
||||
self.bind_shortcuts()
|
||||
|
||||
def create_context_menu(self):
|
||||
self.context_menu = tk.Menu(self, tearoff=0)
|
||||
self.context_menu.add_command(label="Вырезать", command=self.cut)
|
||||
self.context_menu.add_command(label="Копировать", command=self.copy)
|
||||
self.context_menu.add_command(label="Вставить", command=self.paste)
|
||||
self.context_menu.add_separator()
|
||||
self.context_menu.add_command(label="Выделить всё", command=self.select_all)
|
||||
|
||||
self.bind("<Button-3>", self.show_context_menu)
|
||||
|
||||
def show_context_menu(self, event):
|
||||
self.context_menu.post(event.x_root, event.y_root)
|
||||
|
||||
def bind_shortcuts(self):
|
||||
# Стандартные сочетания
|
||||
self.bind("<Control-x>", lambda e: self.event_generate("<<Cut>>"))
|
||||
self.bind("<Control-c>", lambda e: self.event_generate("<<Copy>>"))
|
||||
self.bind("<Control-v>", lambda e: self.event_generate("<<Paste>>"))
|
||||
self.bind("<Control-a>", self.select_all)
|
||||
|
||||
# Shift+Insert для вставки
|
||||
self.bind("<Shift-Insert>", lambda e: self.event_generate("<<Paste>>"))
|
||||
|
||||
# Ctrl+Insert для копирования
|
||||
self.bind("<Control-Insert>", lambda e: self.event_generate("<<Copy>>"))
|
||||
|
||||
# Shift+Delete для вырезания
|
||||
self.bind("<Shift-Delete>", lambda e: self.event_generate("<<Cut>>"))
|
||||
|
||||
def cut(self):
|
||||
self.event_generate("<<Cut>>")
|
||||
|
||||
def copy(self):
|
||||
self.event_generate("<<Copy>>")
|
||||
|
||||
def paste(self):
|
||||
self.event_generate("<<Paste>>")
|
||||
|
||||
def select_all(self, event=None):
|
||||
self.select_range(0, tk.END)
|
||||
return "break"
|
||||
|
||||
class SettingsWindow(tk.Toplevel):
|
||||
def __init__(self, parent, settings, callback=None):
|
||||
super().__init__(parent)
|
||||
@@ -486,13 +586,13 @@ class SettingsWindow(tk.Toplevel):
|
||||
# Размер блока
|
||||
ttk.Label(settings_frame, text="Размер блока:").grid(row=4, column=0, sticky=W, pady=5)
|
||||
self.block_size_var = StringVar(value=str(settings.get("block_size", 15)))
|
||||
block_size_entry = ttk.Entry(settings_frame, textvariable=self.block_size_var)
|
||||
block_size_entry = CustomEntry(settings_frame, textvariable=self.block_size_var)
|
||||
block_size_entry.grid(row=4, column=1, sticky=W, pady=5)
|
||||
|
||||
# Приглашение командной строки
|
||||
ttk.Label(settings_frame, text="Приглашение:").grid(row=5, column=0, sticky=W, pady=5)
|
||||
self.prompt_var = StringVar(value=settings.get("prompt", ">"))
|
||||
prompt_entry = ttk.Entry(settings_frame, textvariable=self.prompt_var)
|
||||
prompt_entry = CustomEntry(settings_frame, textvariable=self.prompt_var)
|
||||
prompt_entry.grid(row=5, column=1, sticky=W, pady=5)
|
||||
|
||||
# Кнопки
|
||||
@@ -551,14 +651,6 @@ class SerialAppGUI(tk.Tk):
|
||||
self.connection = None
|
||||
self.tftp_server = None
|
||||
|
||||
# Глобальные биндинги
|
||||
self.bind_class("Text", "<Control-c>", lambda event: event.widget.event_generate("<<Copy>>"))
|
||||
self.bind_class("Text", "<Control-v>", lambda event: event.widget.event_generate("<<Paste>>"))
|
||||
self.bind_class("Text", "<Control-x>", lambda event: event.widget.event_generate("<<Cut>>"))
|
||||
self.bind_class("Entry", "<Control-c>", lambda event: event.widget.event_generate("<<Copy>>"))
|
||||
self.bind_class("Entry", "<Control-v>", lambda event: event.widget.event_generate("<<Paste>>"))
|
||||
self.bind_class("Entry", "<Control-x>", lambda event: event.widget.event_generate("<<Cut>>"))
|
||||
|
||||
self.create_menu()
|
||||
self.create_tabs()
|
||||
|
||||
@@ -647,13 +739,13 @@ class SerialAppGUI(tk.Tk):
|
||||
ttk.Button(control_frame, text="Подключиться", command=self.connect_device).pack(side=LEFT, padx=5)
|
||||
ttk.Button(control_frame, text="Отключиться", command=self.disconnect_device).pack(side=LEFT, padx=5)
|
||||
|
||||
self.interactive_text = tk.Text(frame, wrap="word", height=20)
|
||||
self.interactive_text = CustomText(frame, wrap="word", height=20)
|
||||
self.interactive_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
input_frame = ttk.Frame(frame)
|
||||
input_frame.pack(fill=X, pady=5)
|
||||
ttk.Label(input_frame, text="Команда:").pack(side=LEFT, padx=5)
|
||||
self.command_entry = ttk.Entry(input_frame, width=50)
|
||||
self.command_entry = CustomEntry(input_frame, width=50)
|
||||
self.command_entry.pack(side=LEFT, padx=5)
|
||||
ttk.Button(input_frame, text="Отправить", command=self.send_command).pack(side=LEFT, padx=5)
|
||||
|
||||
@@ -744,10 +836,10 @@ class SerialAppGUI(tk.Tk):
|
||||
file_frame.pack(fill=X, pady=5)
|
||||
ttk.Label(file_frame, text="Файл конфигурации:").pack(side=LEFT, padx=5)
|
||||
self.file_exec_var = StringVar(value=self.settings.get("config_file") or "")
|
||||
ttk.Entry(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(frame, text="Выполнить команды", command=self.execute_file_commands).pack(pady=5)
|
||||
self.file_exec_text = tk.Text(frame, wrap="word", height=15)
|
||||
self.file_exec_text = CustomText(frame, wrap="word", height=15)
|
||||
self.file_exec_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
def select_config_file_fileexec(self):
|
||||
@@ -793,11 +885,11 @@ class SerialAppGUI(tk.Tk):
|
||||
top_frame.pack(fill=X, pady=5)
|
||||
ttk.Label(top_frame, text="Файл конфигурации:").pack(side=LEFT, padx=5)
|
||||
self.editor_file_var = StringVar(value=self.settings.get("config_file") or "")
|
||||
ttk.Entry(top_frame, textvariable=self.editor_file_var, width=40).pack(side=LEFT, padx=5)
|
||||
CustomEntry(top_frame, textvariable=self.editor_file_var, width=40).pack(side=LEFT, padx=5)
|
||||
ttk.Button(top_frame, text="Выбрать", command=self.select_config_file_editor).pack(side=LEFT, padx=5)
|
||||
ttk.Button(top_frame, text="Загрузить", command=self.load_config_file).pack(side=LEFT, padx=5)
|
||||
ttk.Button(top_frame, text="Сохранить", command=self.save_config_file).pack(side=LEFT, padx=5)
|
||||
self.config_editor_text = tk.Text(frame, wrap="word")
|
||||
self.config_editor_text = CustomText(frame, wrap="word")
|
||||
self.config_editor_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
def select_config_file_editor(self):
|
||||
@@ -868,7 +960,7 @@ class SerialAppGUI(tk.Tk):
|
||||
port_frame.pack(fill=X, padx=5, pady=2)
|
||||
ttk.Label(port_frame, text="Порт:").pack(side=LEFT, padx=5)
|
||||
self.tftp_port_var = StringVar(value="69")
|
||||
self.tftp_port_entry = ttk.Entry(port_frame, textvariable=self.tftp_port_var)
|
||||
self.tftp_port_entry = CustomEntry(port_frame, textvariable=self.tftp_port_var)
|
||||
self.tftp_port_entry.pack(fill=X, expand=True, padx=5)
|
||||
|
||||
# Кнопки управления
|
||||
@@ -894,7 +986,7 @@ class SerialAppGUI(tk.Tk):
|
||||
log_frame = ttk.LabelFrame(tftp_frame, text="Лог сервера")
|
||||
log_frame.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
self.tftp_log_text = tk.Text(log_frame, wrap=tk.WORD, height=10)
|
||||
self.tftp_log_text = CustomText(log_frame, wrap=tk.WORD, height=10)
|
||||
self.tftp_log_text.pack(fill=BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
# Добавляем скроллбар для лога
|
||||
|
||||
Reference in New Issue
Block a user