如何为tkinter文本框创建“自动调整”书签

问题描述 投票:0回答:1

我正在使用tkinter创建功能特定的文本编辑器。我想添加书签功能,并看到了几个使用.yview()[0]或.index(INSERT)的示例,以获取yview的第一行号或应添加书签的行的实际行号。我不知道如何根据对文本框其他部分的行插入/删除来调整书签。我正在使用Bryan Oakley共享的一些很棒的代码来为文本框创建行号。该代码还提供了一个“代理”功能,该功能允许创建虚拟事件来处理不同的tkinter函数(例如,插入,删除,替换等)。这是代码(经过微调以处理不同字体大小的间距):

class TextLineNumbers(tk.Canvas):
    def __init__(self, *args, **kwargs):
        tk.Canvas.__init__(self, *args, **kwargs)
        self.textwidget = None
        self.font_spacing = 0
        self.setfontspacing(self.font_spacing)

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

    def setfontspacing(self, spacing):
        self.font_spacing = spacing

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

        i = self.textwidget.index("@0,0")
        while True :
            dline= self.textwidget.dlineinfo(i)
            if dline is None: break
            y = dline[1] + self.font_spacing
            linenum = str(i).split(".")[0].zfill(7)
            self.create_text(2,y,anchor="nw", text=linenum)
            i = self.textwidget.index("%s+1line" % i)

class CustomText(tk.Text):
    def __init__(self, *args, **kwargs):
        tk.Text.__init__(self, *args, **kwargs)

        # create a proxy for the underlying widget
        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, *args):
        # let the actual widget perform the requested action

        cmd = (self._orig,) + args
        result=None
        try:
            result = self.tk.call(cmd)
        except Exception:
            pass

        # generate an event if something was added or deleted,
        # or the cursor position changed

#        print(cmd, args, "=>", result)

        if (args[0] in ("insert", "replace", "delete") or
            args[0:3] == ("mark", "set", "insert") or
            args[0:2] == ("xview", "moveto") or
            args[0:2] == ("xview", "scroll") or
            args[0:2] == ("yview", "moveto") or
            args[0:2] == ("yview", "scroll")
        ):
            self.event_generate("<<Change>>", when="tail")

        if (args[0] in ("insert", "replace", "delete") ):
            self.event_generate("<<Text_Change>>", when="now")

        # return what the actual widget returned
        return result

我已将Text_Change事件绑定到我的自定义文本窗口小部件,它使我可以跟踪更改(即查看是否已发生更改并在退出时提示进行保存等)。所以那部分工作正常。

但是,这些事件发生时,我不知道如何捕获有关插入/删除的行的详细信息。 print(cmd,args,“ =>”,result)提供了很多细节,我想我可以找到一种基于该信息计算增量的方法,但这似乎是一个复杂的解决方案。

我想知道是否有人解决过这个问题,并且可能会提出建议。或者也许只是我要忽略的一个简单得多的解决方案。

谢谢

python python-3.x tkinter textbox bookmarks
1个回答
1
投票

文本小部件可以通过mark_set命令设置书签。标记可以像文本小部件索引一样使用。例如,您可以在长文件的末尾设置标记“页脚”,然后使用see方法使页脚可见。

标记代表两个索引之间的间隔。如果在索引“ 200.0”处设置标记,则该标记表示先前索引和该索引之间的空间。标记将“粘在”间隙的一侧或另一侧。默认情况下,它的字符会保留在右侧,但是可以使用mark_gravity方法更改该方法,该方法可以接受“左”或“右”。

这里是一个人为设计的示例,该示例在第200行设置了一个书签,然后提供了一个跳转到该标记的按钮。请注意,即使在程序启动后,您也可以插入任意行,并且标记仍将“粘”在单词“ This”(或更确切地说,字母“ T”)上。

import tkinter as tk

root = tk.Tk()
text = tk.Text(root, height=20, yscrollcommand=lambda *args: vsb.set(*args))
vsb = tk.Scrollbar(root, orient="vertical", command=text.yview)
jump = tk.Button(root, text="Jump to bookmark", command=lambda: text.see("bookmark"))

jump.pack(side="top")
vsb.pack(side="right", fill="y")
text.pack(side="left", fill="both", expand=True)

for i in range(300):
    text.insert("end", f"Lorem ipsum dolar set\n")
text.insert("200.0", "This line is bookmarked\n")
text.mark_set("bookmark", "200.0")

root.mainloop()
© www.soinside.com 2019 - 2024. All rights reserved.