简体   繁体   English

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

[英]line number spacing in text widget Tkinter

I am adding line number feature to the text widget by following Bryan Oakley's code here . 我在这里按照Bryan Oakley的代码文本小部件中添加行号功能。 I am inserting my own XML file in that text box. 我在该文本框中插入自己的XML文件。 That file is listed below: 该文件如下:

myFile.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 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()

What I want: 我想要的是:

The result generated on running code looks like this: 运行代码生成的结果如下所示:

在此输入图像描述

I have edited this pic using ms-paint to show red markings. 我用ms-paint编辑了这张照片,以显示红色标记。 Numbering of lines in red is what I want. 用红色编号是我想要的。 As it can be seen that numbering on canvas also includes space, I want to modify code in such a manner that there are no line numbers on empty or white spaces. 由于可以看出画布上的编号也包括空格,我想以这样的方式修改代码,即空白或空白空间上没有行号。

So there are two objectives I want to achieve: 所以我想实现两个目标:

1). 1)。 Follow line numbering in a way numbers marked in red are given. 按照以红色标记的数字的方式跟随行号。

2). 2)。 After this changes are made if possible I also want to extract the line number from canvas for any given string for that text widget. 在可能的情况下进行此更改之后,我还想从canvas获取该文本小部件的任何给定字符串的行号。

What I tried 我尝试了什么

I am trying to compare two files and introduce empty lines on places where there are missing points. 我试图比较两个文件,并在缺少点的地方引入空行。 Before I proceed I need to implement an algorithm which can exclude empty white space from allotting line numbers (which happens with most of the editors). 在我继续之前,我需要实现一个算法,该算法可以从分配行号中排除空白空间(大多数编辑器都会这样做)。 So far I am playing around but cannot find how can I implement this in code above. 到目前为止,我正在玩,但无法找到如何在上面的代码中实现这一点。

Hopefully, Bryan Oakley will see your question and post an eloquent solution. 希望Bryan Oakley会看到你的问题并发布一个雄辩的解决方案。 But in the mean time, this somewhat hacky approach works. 但与此同时,这种有点黑客的方法也起作用。 :) :)

On each redraw, we grab the current text contents of the widget, and build a dictionary that uses the index of each non-blank line as the key in a dictionary that holds the actual line numbers we want. 在每次重绘时,我们获取窗口小部件的当前文本内容,并构建一个字典,该字典使用每个非空行的索引作为字典中的键,该字典包含我们想要的实际行号。

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)

If you un-comment the #print num, linetext, line it will print each non-blank line with its number on every redraw. 如果取消注释#print num, linetext,它将在每次重绘时打印每个非空白行及其编号。 You probably don't want that, but it should help you to figure out how to extract the line numbers for a given line. 您可能不希望这样,但它应该可以帮助您弄清楚如何提取给定行的行号。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM