英语:我需要对右侧框架中编辑文本的文本使用撤消和重做。我尝试了多种方法但没能成功,它只是没有做任何事情,没有错误,什么也没有。 我会留下代码,以便您可以帮助我
西班牙语:necesito utilizar el undo y redo para el texto que está en el frame derecho, donde se edita el texto。他 probado de multiples formas y no he podido, simplemente no hace nada, no hay errores, no hay nada。 dejare el código para que puedan hacharme una mano
import tkinter as tk
from tkinter import messagebox, filedialog, Scrollbar, TOP, X, RIGHT, Y, BOTH, LEFT, Text
import sqlite3
from PIL import Image, ImageTk
from email.message import EmailMessage
import smtplib
from docx import Document
import os
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Paragraph
from docx.shared import Pt
class MasterPanel:
def __init__(self):
self.ventana = tk.Tk()
self.ventana.title('Master panel')
# Configuración de la ventana
w, h = self.ventana.winfo_screenwidth(), self.ventana.winfo_screenheight()
w -= 10
h -= 55
self.ventana.geometry("%dx%d+0+0" % (w, h))
self.ventana.config(bg='#e8cebd')
self.ventana.resizable(width=0, height=0)
# Crear el frame principal
main_frame = tk.Frame(self.ventana)
main_frame.pack(fill='both', expand=True)
# Frame izquierdo para el menú y la lista de documentos
self.frame_izquierdo = tk.Frame(main_frame, bg='white', width=200)
self.frame_izquierdo.pack(side='left', fill='both', expand=False)
# Frame derecho para mostrar y editar el documento
self.frame_derecho = tk.Frame(main_frame, bg='lightgrey')
self.frame_derecho.pack(side='right', fill='both', expand=True)
# Barra de herramientas
self.crear_barra_herramientas()
# Obtener documentos desde la base de datos
documentos = self.consultar_documentos()
self.undo_stack = [] # Inicialización de la pila de deshacer
self.redo_stack = [] # Inicialización de la pila de rehacer
# Mostrar los documentos en el frame izquierdo
label_menu = tk.Label(self.frame_izquierdo, text='Documentos', font=('Arial', 12), bg='white')
label_menu.pack(pady=20)
self.listbox_documentos = tk.Listbox(self.frame_izquierdo, width=30, height=10)
for documento in documentos:
self.listbox_documentos.insert(tk.END, documento[0]) # Mostrar solo el nombre del documento
self.listbox_documentos.pack(padx=20, pady=10, fill='both', expand=True)
self.listbox_documentos.bind("<<ListboxSelect>>", self.mostrar_documento_seleccionado)
def show_context_menu(self, event):
self.context_menu.tk_popup(event.x_root, event.y_root)
def apply_tag(self, tag_name, tag_property):
try:
# Obtener el texto seleccionado
start_index = self.text_documento.index("sel.first")
end_index = self.text_documento.index("sel.last")
self.text_documento.tag_add(tag_name, start_index, end_index)
self.text_documento.tag_config(tag_name, font=(None, 12, tag_property))
except tk.TclError:
messagebox.showinfo("Error", "Por favor, selecciona texto primero.")
def toggle_bold(self):
self.remove_formatting()
self.apply_tag("bold", "bold")
def toggle_italic(self):
self.remove_formatting()
self.apply_tag("italic", "italic")
def toggle_underline(self):
self.remove_formatting()
self.apply_tag("underline", "underline")
def remove_formatting(self):
self.text_documento.tag_remove("bold", "sel.first", "sel.last")
self.text_documento.tag_remove("italic", "sel.first", "sel.last")
self.text_documento.tag_remove("underline", "sel.first", "sel.last")
def crear_barra_herramientas(self):
# Barra de herramientas
barra_menus = tk.Menu(self.ventana)
self.ventana.config(menu=barra_menus)
self.barra_menus = barra_menus
# Menú Archivo
menu_archivo = tk.Menu(barra_menus, tearoff=0)
menu_archivo.add_command(
label="Guardar",accelerator="Ctrl+S", compound="left",command=self.guardar_documento)
self.ventana.bind_all("<Control-s>", self.guardar_documento)
menu_archivo.add_separator()
menu_archivo.add_command(
label="Subir a Base de Datos",accelerator="Ctrl+O",compound="left",command=self.subir_documento)
self.ventana.bind_all("<Control-o>", self.subir_documento)
barra_menus.add_cascade(menu=menu_archivo, label="Archivo")
# Crear el nuevo menú "Edición" y añadir opciones dentro
menu_edicion = tk.Menu(self.ventana, tearoff=0)
menu_edicion.add_command(label="Deshacer", command=self.undo_action, accelerator="Ctrl+Z")
self.ventana.bind_all("<Control-z>", self.undo_action) # Asignar atajo de teclado a Deshacer
menu_edicion.add_command(label="Rehacer", command=self.redo_action, accelerator="Ctrl+Y")
self.ventana.bind_all("<Control-y>", self.redo_action) # Asignar atajo de teclado a Rehacer
# Agregar el nuevo menú "Edición" al menú principal
self.barra_menus.add_cascade(menu=menu_edicion, label="Edición")
def guardar_documento(self, event=None):
# Obtener el contenido actual del documento
contenido_actual = self.text_documento.get('1.0', tk.END)
# Ventana para seleccionar la ruta de guardado
file_path = filedialog.asksaveasfilename(defaultextension=".docx", filetypes=[("Word Document", "*.docx"),
("PDF", "*.pdf")])
if file_path.endswith('.docx'):
doc = Document()
# Configurar el estilo del documento DOCX
style = doc.styles['Normal']
font = style.font
font.name = 'Times New Roman'
font.size = Pt(12)
# Añadir el contenido al documento con formato
for line in contenido_actual.split('\n'):
p = doc.add_paragraph(line.strip())
p.alignment = 3 # 3 representa el justificado
# Guardar como archivo DOCX
doc.save(file_path)
elif file_path.endswith('.pdf'):
doc = SimpleDocTemplate(file_path, pagesize=letter)
# Configurar el estilo del documento PDF
style = getSampleStyleSheet()["Normal"]
style.fontName = 'Times-Roman'
style.fontSize = 12
# Añadir el contenido al documento con formato
content = []
for line in contenido_actual.split('\n'):
content.append(Paragraph(line.strip(), style))
# Crear el PDF con contenido justificado
doc.build(content)
# Enviar correo electrónico
if self.enviar_correo(file_path):
messagebox.showinfo("Correo Enviado",
"El documento ha sido guardado en la dirección "
"establecida.")
def subir_documento(self, event=None):
os.system('python BD.py')
# Recargar los documentos desde la base de datos
documentos = self.consultar_documentos()
# Limpiar la lista actual de documentos
self.listbox_documentos.delete(0, tk.END)
# Agregar los nuevos documentos a la lista
for documento in documentos:
self.listbox_documentos.insert(tk.END, documento[0])
def consultar_documentos(self):
# Conectar a la base de datos
conexion = sqlite3.connect('documentos.db')
cursor = conexion.cursor()
# Ejecutar la consulta para obtener los nombres de los documentos
cursor.execute("SELECT nombre_documento FROM documentos")
documentos = cursor.fetchall()
# Cerrar la conexión a la base de datos
conexion.close()
return documentos
def mostrar_documento_seleccionado(self, event):
seleccion = self.listbox_documentos.curselection()
if seleccion:
nombre_documento = self.listbox_documentos.get(seleccion)
contenido_documento = self.obtener_contenido_documento(nombre_documento)
self.mostrar_docx_en_frame(contenido_documento)
def obtener_contenido_documento(self, nombre_documento):
# Conectar a la base de datos
conexion = sqlite3.connect('documentos.db')
cursor = conexion.cursor()
# Ejecutar la consulta para obtener el contenido del documento seleccionado
cursor.execute("SELECT contenido FROM documentos WHERE nombre_documento = ?", (nombre_documento,))
contenido = cursor.fetchone()[0]
# Cerrar la conexión a la base de datos
conexion.close()
return contenido
def mostrar_docx_en_frame(self, contenido_docx):
# Limpiar el frame derecho antes de mostrar el nuevo documento
for widget in self.frame_derecho.winfo_children():
widget.destroy()
# Crear un widget Text para mostrar y editar el documento .docx
self.text_documento = Text(self.frame_derecho, wrap='word')
self.text_documento.insert('1.0', contenido_docx)
self.text_documento.pack(fill=BOTH, expand=True)
# Configurar scrollbar para el texto del documento
scrollbar = Scrollbar(self.text_documento)
scrollbar.pack(side=RIGHT, fill=Y)
scrollbar.config(command=self.text_documento.yview)
self.text_documento.config(yscrollcommand=scrollbar.set)
# Crear el menú contextual para el widget Text
self.context_menu = tk.Menu(self.ventana, tearoff=0)
self.context_menu.add_command(label="Negrita", command=self.toggle_bold)
self.context_menu.add_command(label="Cursiva", command=self.toggle_italic)
self.context_menu.add_command(label="Subrayado", command=self.toggle_underline)
self.context_menu.add_command(label="Quitar todo", command=self.remove_formatting)
# Vincular el menú contextual al evento del botón derecho del ratón
self.text_documento.bind("<Button-3>", self.show_context_menu)
self.text_documento.bind("<Control-z>", self.undo_action)
self.text_documento.bind("<Control-y>", self.redo_action)
def undo_action(self, event=None):
try:
self.text_documento.edit_undo()
except tk.TclError:
messagebox.showinfo("No se puede deshacer", "No hay acciones para deshacer.")
def redo_action(self, event=None):
try:
self.text_documento.edit_redo()
except tk.TclError:
messagebox.showinfo("No se puede rehacer", "No hay acciones para rehacer.")
if __name__ == "__main__":
app = MasterPanel()
app.ventana.mainloop()
我觉得错误可能出在以下部分之一:
# Crear el nuevo menú "Edición" y añadir opciones dentro
menu_edicion = tk.Menu(self.ventana, tearoff=0)
menu_edicion.add_command(label="Deshacer", command=self.undo_action, accelerator="Ctrl+Z")
self.ventana.bind_all("<Control-z>", self.undo_action) # Asignar atajo de teclado a Deshacer
menu_edicion.add_command(label="Rehacer", command=self.redo_action, accelerator="Ctrl+Y")
self.ventana.bind_all("<Control-y>", self.redo_action) # Asignar atajo de teclado a Rehacer
# Agregar el nuevo menú "Edición" al menú principal
self.barra_menus.add_cascade(menu=menu_edicion, label="Edición")
def undo_action(self, event=None):
try:
self.text_documento.edit_undo()
except tk.TclError:
messagebox.showinfo("No se puede deshacer", "No hay acciones para deshacer.")
def redo_action(self, event=None):
try:
self.text_documento.edit_redo()
except tk.TclError:
messagebox.showinfo("No se puede rehacer", "No hay acciones para rehacer.")
def mostrar_docx_en_frame:
self.text_documento.bind("<Control-z>", self.undo_action)
self.text_documento.bind("<Control-y>", self.redo_action)