文本小部件Tkinter中的行号间距

时间:2015-11-06 11:18:55

标签: python xml tkinter

我正在按照Bryan Oakley的代码here向文本小部件添加行号功能。我在该文本框中插入自己的XML文件。该文件列在下面:

myfile.xml中

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

<p1:sample1 xmlns:p1="http://www.example.org/eHorizon">

   <p1:time nTimestamp="5">
      <p1:location hours = "1" path = '1'>
         <p1:feature color="6" type="a">560</p1:feature>
         <p1:feature color="2" type="a">564</p1:feature>
         <p1:feature color="3" type="b">570</p1:feature>
         <p1:feature color="4" type="c">570</p1:feature>
      </p1:location>
   </p1:time>

   <p1:time nTimestamp="6">
      <p1:location hours = "1" path = '1'>
         <p1:feature color="2" type="a">564</p1:feature>
         <p1:feature color="3" type="b">570</p1:feature>
         <p1:feature color="4" type="c">570</p1:feature>
      </p1:location>
   </p1:time>

</p1:sample1>

myCode.py

import Tkinter as tk

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

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

    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]
            linenum = str(i).split(".")[0]
            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)

        self.tk.eval('''
            proc widget_proxy {widget widget_command args} {

                # call the real tk widget command with the real args
                set result [uplevel [linsert $args 0 $widget_command]]

                # generate the event for certain types of commands
                if {([lindex $args 0] in {insert replace delete}) ||
                    ([lrange $args 0 2] == {mark set insert}) || 
                    ([lrange $args 0 1] == {xview moveto}) ||
                    ([lrange $args 0 1] == {xview scroll}) ||
                    ([lrange $args 0 1] == {yview moveto}) ||
                    ([lrange $args 0 1] == {yview scroll})} {

                    event generate  $widget <<Change>> -when tail
                }

                # return the result from the real widget command
                return $result
            }
            ''')
        self.tk.eval('''
            rename {widget} _{widget}
            interp alias {{}} ::{widget} {{}} widget_proxy {widget} _{widget}
        '''.format(widget=str(self)))

class Example(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        self.text = CustomText(self)
        self.vsb = tk.Scrollbar(orient="vertical", command=self.text.yview)
        self.text.configure(yscrollcommand=self.vsb.set)
        self.text.tag_configure("bigfont", font=("Helvetica", "24", "bold"))
        self.linenumbers = TextLineNumbers(self, width=30)
        self.linenumbers.attach(self.text)

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

        self.text.bind("<<Change>>", self._on_change)
        self.text.bind("<Configure>", self._on_change)
        file = open('C:/your/file/location/myFile.xml')
        self.text.insert("end", file.read())


    def _on_change(self, event):
        self.linenumbers.redraw()

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

我想要的是什么:

运行代码时生成的结果如下所示:

enter image description here

我使用ms-paint编辑了这张照片以显示红色标记。用红色编号是我想要的。可以看出画布上的编号也包含空格,我想修改代码,使得空格或空格上没有行号。

所以我想实现两个目标:

1)。按照红色标记的方式跟随行号。

2)。在可能的情况下进行此更改之后,我还想从canvas获取该文本小部件的任何给定字符串的行号。

我尝试了什么

我正在尝试比较两个文件,并在缺少点的地方引入空行。在我继续之前,我需要实现一个算法,该算法可以从分配行号中排除空白空间(大多数编辑器都会这样做)。到目前为止,我正在玩,但无法找到如何在上面的代码中实现这一点。

1 个答案:

答案 0 :(得分:3)

希望Bryan Oakley会看到你的问题并发布一个雄辩的解决方案。但与此同时,这种有点黑客的方法也起作用。 :)

在每次重绘时,我们获取窗口小部件的当前文本内容,并构建一个字典,该字典使用每个非空行的索引作为字典中的键,该字典包含我们想要的实际行号。

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

    # Build dict to convert line index to line number
    linenums = {}
    num = 1
    contents = self.textwidget.get("1.0", tk.END)
    for i, line in enumerate(contents.splitlines(), 1):
        i = str(i) + '.0'
        # Only increment line number if the line's not blank
        linetext = self.textwidget.get(i, "%s+1line" % i)
        if linetext.strip():
            linenums[i] = str(num)
            #print num, linetext,
            num += 1

    i = self.textwidget.index("@0,0")
    while True :
        dline = self.textwidget.dlineinfo(i)
        if dline is None: 
            break

        linenum = linenums.get(i)
        if linenum is not None:
            y = dline[1]
            self.create_text(2,y,anchor="nw", text=linenum)

        i = self.textwidget.index("%s+1line" % i)

如果您取消评论#print num, linetext,行,则会在每次重绘时打印每个非空行及其编号。您可能不希望如此,但它应该可以帮助您弄清楚如何提取给定行的行号。