如何复制 tkinter 小部件?

问题描述

如何复制 tkinter 文本小部件,以便您可以将其添加到每个 Notebook 选项卡中?我正在使用 tkinter 编写编辑器,并且还添加了撤消功能。问题是,当我添加一个新选项卡时,撤消功能仅适用于该选项卡。当我删除该选项卡时,它也不适用于其他选项卡。

from tkinter.ttk import Notebook
import tkinter.messageBox


class TextClass(Frame):
    def __init__(self,*args,**kwargs):
        Frame.__init__(self,**kwargs)

        self.text = Text(self,bg='white',foreground="black",undo=True,insertbackground='black',height=35,width=135,selectbackground="blue")

        self.scrollbar = Scrollbar(self,orient=VERTICAL,command=self.text.yview)
        self.text.configure(yscrollcommand=self.scrollbar.set)

        self.numberLines = TextLineNumbers(self,width=40,bg='#2A2A2A')
        self.numberLines.attach(self.text)

        self.scrollbar.pack(side=RIGHT,fill=Y)
        self.numberLines.pack(side=LEFT,fill=Y,padx=(5,0))
        self.text.pack(fill='both',expand=True)

        self.text.bind("<Key>",self.onPressDelay)
        self.text.bind("<Button-1>",self.numberLines.redraw)
        self.scrollbar.bind("<Button-1>",self.onScrollPress)
        self.text.bind("<MouseWheel>",self.onPressDelay)

        def undo():

            try:
                self.text.edit_undo()

            except TclError:
                tkinter.messageBox.showerror(
                    "nothing to Undo","You have not typed anything to undo. Please type and try again!"
                )

        undo_button = Button(toolbar,text='Undo',relief='ridge',command=undo,bg='black',fg='white',width=6)
        undo_button.place(x=170,y=5)
        hover(undo_button,on_entrance='white',on_exit='black',entrance_foreground='black',exit_fg='white')

        def redo():

            try:
                self.text.edit_redo()

            except TclError:
                tkinter.messageBox.showerror(
                    "nothing to Redo","You have not done an undo to redo. Please type and try again!"
                )

        redo_button = Button(toolbar,text='Redo',command=redo,width=6)
        redo_button.place(x=230,y=5)
        hover(redo_button,exit_fg='white')

    def onScrollPress(self,*args):
        self.scrollbar.bind("<B1-Motion>",self.numberLines.redraw)

    def onScrollRelease(self,*args):
        self.scrollbar.unbind("<B1-Motion>",self.numberLines.redraw)

    def onPressDelay(self,*args):
        self.after(2,self.numberLines.redraw)

    def get(self,**kwargs):
        return self.text.get(*args,**kwargs)

    def insert(self,**kwargs):
        return self.text.insert(*args,**kwargs)

    def delete(self,**kwargs):
        return self.text.delete(*args,**kwargs)

    def index(self,**kwargs):
        return self.text.index(*args,**kwargs)

    def redraw(self):
        self.numberLines.redraw()


class TextLineNumbers(Canvas):
    Canvas.text_widget = None

    def attach(self,text_widget):
        self.text_widget = text_widget

    def redraw(self,*args):
        self.delete("all")

        i = self.text_widget.index("@0,0")
        while True:
            d_line = self.text_widget.dlineinfo(i)
            if d_line is None:
                break
            y = d_line[1]
            line_numbers = str(i).split(".")[0]
            self.create_text(2,y,anchor="nw",text=line_numbers,fill="white")
            i = self.text_widget.index("%s+1line" % i)

def add_tab():
    global tab
    tab = Frame(notebook)
    notebook.add(tab,text=f'{"Untitled1.txt": ^20}')
    global text
    text = TextClass(tab,bg='white')
    text.pack()
    text.text.focus()


def close_tab():
    notebook.forget('current')

def hover(widget,entrance_foreground,exit_fg,on_entrance,on_exit):
    widget.bind("<Enter>",func=lambda e: widget.config(
        bg=on_entrance,fg=entrance_foreground
    ))

    widget.bind("<Leave>",func=lambda e: widget.config(
        bg=on_exit,fg=exit_fg
    ))


root = Tk()
root.config(bg='white')
root.geometry("1260x680")

toolbar = Frame(root,height=45)
toolbar.pack(expand=False,fill='x')

notebook = Notebook(root)
tab = Frame(notebook)
notebook.add(tab,text=f'{"Untitled.txt": ^20}')
notebook.place(x=50,y=60)


text = TextClass(tab,bg='white')
text.pack()

add_tab_btn = Button(toolbar,text='Add new tab',command=add_tab,fg='white')
hover(add_tab_btn,exit_fg='white')
add_tab_btn.place(x=15,y=5)

delete_tab_btn = Button(toolbar,text='Delete tab',command=close_tab,fg='white')
hover(delete_tab_btn,exit_fg='white')
delete_tab_btn.place(x=100,y=5)

root.after(200,text.redraw())
scr_menu()
root.mainloop()

解决方法

我怀疑您每次创建新标签时都会在旧按钮上制作新的撤消/重做按钮。这意味着该按钮仅适用于最后一个选项卡。要解决该问题,您必须移动笔记本内的撤消/重做按钮。正如概念证明改变这一行:

undo_button = Button(toolbar,text='Undo',relief='ridge',command=undo,bg='black',fg='white',width=6)

undo_button = Button(self,width=6)