zoukankan      html  css  js  c++  java
  • GUI的最终选择 Tkinter(五):Text用法

    Text组件

    绘制单行文本使用Label组件,多行选使用Listbox,输入框使用Entry,按钮使用Button组件,还有Radiobutton和Checkbutton组件用于提供单选或多选的情况,多个组件可以使用Frame组件先搭建一个框架,这样组合起来显示好看点,最后还学习了Scrollbar和Scale,Scrollbar组件用于实现滚动条,而Scale则是让用户在一个范围内选择一个确定的值。

    Text(文本)组件用于显示和处理多行文本。在Tkinter的所有组件中,Text组件显得异常强大和灵活,它适用于处理多种任务,虽然该组件的蛀牙牡蛎是显示多行文本,但它长城被用于作为简单的文本编辑器和网页浏览器使用。

    当创建一个Text组件的时候,它里面是没有内容的,为了给其插入内容,可以利用insert()方法以及INSERT或END索引号:

    1 from tkinter import *
    2 
    3 root = Tk()
    4 text = Text(root,width=20,height=15)
    5 text.pack()
    6 text.insert(INSERT,"Python3 
    ") #INSERT索引表示插入光标当前的位置
    7 text.insert(END,"python算法")
    8 mainloop()

    执行结果:

    Text组件不仅支持插入和编辑文本,它还支持插入image对象和windows组件。

     1 from tkinter import *
     2 
     3 root = Tk()
     4 text = Text(root,width=20,height=15)
     5 text.pack()
     6 text.insert(INSERT,"I love Python3") #INSERT索引表示插入光标当前的位置
     7 def show():
     8     print("被点了一下。。。")
     9 b1 = Button(text,text="点我",command=show)
    10 text.window_create(INSERT,window=b1)
    11 mainloop()

     执行结果:

    下面代码将实现单击显示一张图片

     1 from tkinter import *
     2 
     3 root = Tk()
     4 text = Text(root,width=20,height=15)
     5 text.pack()
     6 photo = PhotoImage(file='bg.gif')
     7 def show():
     8     text.image_create(END,image=photo)
     9 b1 = Button(text,text="点我",command=show)
    10 text.window_create(INSERT,window=b1)
    11 mainloop()

    执行结果:

    Indexes用法

    Indexes(索引)是用来指向Text组件中文本的位置,跟Python的序列索引一样,Text组件索引也是对应实际字符之间的位置。

    Tkinter提供一系列不同的索引类型:

    • “line.column”(行/列)
    • “line.end”(某一行的末尾)
    • INSERT
    • CURRENT
    • END
    • user-defined marks
    • user-defined tags("tag.first","tag.last")
    • selection(SELFIRST.SELLAST)
    • window coordinate("@x,y")
    • embedded object name(window,images)
    • expressions

    1. "line.column‘’

    用行号和列号组成的字符串是常用的索引方法,它们将索引位置的行号和列号以字符串的形式表示出来(中间以“.”分隔,例如“1.0”)。需要注意的是:行号以1开始,列号则以0开始,还可以使用一下语法建索引:

    “%d.%d”%(line,column)

    指定超出现有文本的最后一行的行号,或超出一行中列数的列号都不会引发错误。对于这样的指定,Tkinter解释为已有内容的末尾的下一个位置。

    需要注意的是,使用“行/列”的索引方式看起来像是浮点值,其实在需要指定索引的时候使用浮点值代替也是可以的:

     1 from tkinter import *
     2 
     3 root = Tk()
     4 text = Text(root,width=20,height=15)
     5 text.pack()
     6 def show():
     7     text.insert(INSERT, "i love python")
     8     print(text.get("1.2", 1.6))
     9 b1 = Button(text,text="点我",command=show)
    10 text.window_create(INSERT,window=b1)

    执行结果:

    2. “line.end”

    行号加上字符串“.end”的格式表示该行最后一个字符串的位置:

    from tkinter import *
    
    root = Tk()
    text = Text(root,width=20,height=15)
    text.pack()
    def show():
        text.insert(INSERT, "i love python")
        print(text.get("1.2", "1.end"))
    b1 = Button(text,text="点我",command=show)
    text.window_create(INSERT,window=b1)
    
    mainloop()

    执行结果:

    3. INSERT(或“insert”)

    对应插入光标的位置

    4. CURRENT(或“current”)

    对应与鼠标坐标最接近的位置。不过,如果你紧按鼠标任何一个按钮,会直接到你松开才相应。

    5. END(或“end”)

    对应Text组件的文本缓冲区最后一个字符的下一个位置。

    6. user-defined marks

    user-defined marks是对Text组件中位置的命名。INSERT和CURRENT是两个预先命名好的marks,除此之外可以自定义marks。

    7. User-defined tags

    User-defined tags代表可以分配给Text组件的特殊事件绑定和风格。、

    可以使用“tag.first”(使用tag的未必能是第一个字符之间)和“tag.last”(使用tag的文本的最后一个字符之后)语法表示标签的范围:

    “%s.first”%tagname 
    
    “%s.last”%tagnam 

    8. selection(SELFIRST,SELLAST)

    selection是一个名为SEL(或“sel”)的特殊tag,表示当前被选中的范围,可以使用SELFIRST和SELLAST来表示这个范围如果没有选中的内容,那么Tkinter会抛出一个TclError异常。

    9. windows coordinate("@x.y")

    可以使用串口坐标作为索引。例如在一个时间绑定中,你可以使用以下代码找到最接近的鼠标字符:

    “@%d,%d”%(event.x,event.y)

    10. embedded object name(window,images)

    embedden object name 用于指向在Text组件中嵌入的window和image对象。要引用一个window,只要简单地讲一个Tkinter组件实例作为索引即可。引用一个嵌入的image,只需要使用相应的PhotoImage和BitmapImage对象。

    11. expressions

    expressions用于修改任何格式的索引,用字符串的形式实现修改索引的表达式,具体表达式实现如表:

    表达式 含义
    "+count chars" 将索引向前(->)移动count个字符。可以越过换行符,但不能超过END的位置
    "-count chars" 将索引向后(<-)移动count个字符。可以越过换行符,但不能超过"1.0"的位置
    "+count lines" 将索引向前(->)移动count行,索引会尽量保持与移动前在同一列上,但如果移动后的那一行字符太少,将移动到该行的末尾。
    "-count lines" 将索引向后(,-)移动count行,索引会尽量保持与移动前在同一列上,但如果移动后的那一行字符太少,将移动到该行的末尾。
    "linestart" 将索引移动到当前索引所在行的起始位置。注意:使用的该表达式前面必须用一个空格隔开
    "lineend" 将索引移动到当前索引所在行的末尾位置。注意:使用的该表达式前面必须用一个空格隔开
    "wordstart" 将索引移动到当前索引指向的单词的开头。单词的定义是一系列字母、数字、下划线或任何为空白字符的组合。注意:使用该表达式前面必须用一个空格隔开
    "wordend" 将索引移动到当前索引指向的单词的末尾。单词的定义是一系列字母、数字、下划线或任何为空白字符的组合。注意:使用该表达式前面必须用一个空格隔开

    提示:只要结果不产生歧义,关键字可以被缩写,空格可以是省略的,例如:“+ 5chars”可以缩写为“+5c”

    在实现中,为了确保表达式为普通字符串,你可以使用str或格式化操作来创建一个表达式字符串。来看下面列子,删除插入光标前面的一个字符。

    def backspace(event):
        event.widgt.delete("%s-1c"%INSERT,INSERT)

    Marks用法

    Marks通常是指嵌入到Text组件文本中的不可见对象,简单的说就是指定字符串间的位置,它会跟着相应的字符一起移动。Marks有INSERT,CURRENT和user-defined marks(用户自定义的Marks)。其中,INSERT和CURRENT是Tkinter预定义的特殊Marks,它不能够被删除。

    INSERT(或insert)用于指定当前插入的光标的而为之,Tkinter会在该位置绘制一个闪烁的光标(因此并不是所有的Marks都不可见)。

    CURRENT(或current)用于指定与与鼠标坐标最接近的位置。不过,如果你紧按鼠标任何一个按钮,它会知道你松开才响应。

    还可以自定义任意数量的Marks,Marks的名字是由普通字符串组成,可以是除了空白字符的任何字符(为了避免歧义,你应该起一个有意义的名字),使用mark_ser()方法创建和移动Marks.

    如果在一个Marks标记的位置之前插入或删除文本,那么Marks跟着一并移动,删除Marks需要使用mark_unset()方法,删除Marks周围的文本并并不会删除Marks本身。

    其实Marks事实上就是索引,用于表示位置:

    1 from tkinter import *
    2 root = Tk()
    3 text = Text(root,width=30,height=10)
    4 text.pack()
    5 text.insert(INSERT,'I love python')
    6 text.mark_set("here","1.2")
    7 text.insert('here',"")
    8 mainloop()

    执行结果:

    再如,如果Marks前边的内容发生改变,那么Marks的位置也会跟着移动(实际上,就是Mark会记住它后面的内容)

    1 from tkinter import *
    2 root = Tk()
    3 text = Text(root,width=30,height=10)
    4 text.pack()
    5 text.insert(INSERT,'I love python')
    6 text.mark_set("here","1.2")
    7 text.insert('here',"")
    8 text.insert('here',"")
    9 mainloop()

    执行结果:

    再如,如果Marks周围的文本被删了,Mark仍然在:

     1 from tkinter import *
     2 root = Tk()
     3 text = Text(root,width=30,height=10)
     4 text.pack()
     5 text.insert(INSERT,'I love python')
     6 text.mark_set("here","1.2")
     7 text.insert('here',"")
     8 text.delete('1.0',END)
     9 text.insert('here',"")
    10 mainloop()

    执行结果:

    再如,只有mark_unset()方法可以解除Mark的封印;

     1 from tkinter import *
     2 root = Tk()
     3 text = Text(root,width=30,height=10)
     4 text.pack()
     5 text.insert(INSERT,'I love python')
     6 text.mark_set("here","1.2")
     7 text.insert('here',"")
     8 text.mark_unset("here")
     9 text.delete('1.0',END)
    10 text.insert('here',"")
    11 mainloop()

    错误信息:

    ---------------------------------------------------------------------------
    TclError                                  Traceback (most recent call last)
    <ipython-input-7-2c32c5656dea> in <module>()
          8 text.mark_unset("here")
          9 text.delete('1.0',END)
    ---> 10 text.insert('here',"")
         11 mainloop()
    
    c:python36lib	kinter\__init__.py in insert(self, index, chars, *args)
       3264         """Insert CHARS before the characters at INDEX. An additional
       3265         tag can be given in ARGS. Additional CHARS and tags can follow in ARGS."""
    -> 3266         self.tk.call((self._w, 'insert', index, chars) + args)
       3267     def mark_gravity(self, markName, direction=None):
       3268         """Change the gravity of a mark MARKNAME to DIRECTION (LEFT or RIGHT).
    
    TclError: bad text index "here"

    默认插入内容到Mark,是插入到他的左侧(就是说插入一个字符的话,Mark向后移动了一个字符的位置)。那么能不能插入到Mark的右侧了?答案是可以的,通过mark_gravity()方法就可以实现。 

    Tags用法

     Tags(标签)通常用于改变Text组件中内容的样式和功能。可以用来修改文本的字体,尺寸和颜色。另外,Tags还允许将文本,嵌入的组件和图片与键盘鼠标等事件相关联。除了user-defined tags(用户自定义的Tags),还有一个预定义的特殊Tags:SEL.

    SEL(或sel)用于表示对象的选中内容(如果有的话)

    可以自定义任意数量的Tags,Tags的名字是有普通字符串组成,可以是除了空白字符以外的额任意字符。另外,任何文本内容都支持多个Tags描述,任何Tags也可以用于描述多个不同的文本内容。

    为指定文本添加Tags可以使用tag_add()方法:

    1 from tkinter import *
    2 root = Tk()
    3 text = Text(root,width=30,height=10)
    4 text.pack()
    5 text.insert(INSERT,'I love python3.6')
    6 text.tag_add("tag1","1.7","1.12","1.14")
    7 text.tag_config("tag1",background="yellow",foreground="red")
    8 mainloop()

    执行结果:

    如上,使用tag_config()方法可以设置Tags的样式。下表列举了tag_config()可以使用的选项。

    如上,使用 tag_config() 方法可以设置 Tags 的样式。下面罗列了 tag_config() 方法可以使用的选项:

    选项含义
    background

    ①指定该Tag所描述的内容的背景颜色

    ②注意:bg并不是该选项的缩写,在这里bg被解释成bgstipple选项的缩写

    bgstipple

    ①指定一个位图作为背景,并使用background选项指定的颜色填充

    ②只有设定了background选项,该选项才会生效

    ③默认的标准位图有:'error', 'gray75', 'gray50', 'gray25', 'gray12', 'hourglass', 'info', 'questhead', 'question'和'warning'

    borderwidth

    ①指定文本框的宽度

    ②默认值是0

    ③只有设定了relief选项该选项才会生效

    ④注意:该选项不能使用bd缩写

    fgstipple

    ①指定一个位图作为前景色

    ②默认的标准位图有:'error', 'gray75', 'gray50', 'gray25', 'gray12', 'hourglass', 'info', 'questhead', 'question'和'warning'

    font ①指定该Tag所描述的内容使用的字体
    foreground

    ①指定该Tag所描述的内容使用的前景色

    ②注意:fg并不是该选项的缩写,在这里fg被解释为fgstipple的缩写

    justify

    ①控制文本的对齐方式

    ②默认是LEFT(左对齐),还可以选择RIGHT(右对齐)和CENTER(居中)

    ③注意:需要将Tag指向该行的第一个字符,该选项才能生效

    Imargin1

    ①设置Tag指向的文本块第一行的缩进

    ②默认值是0

    ③注意:需要将Tag指向该行的第一个字符或整个文本块,该选项才能生效

    Imargin2

    ①设置Tag指向的文本块除了第一行其他行的缩进

    ②默认值是0

    ③注意:需要将Tag指向整个文本块,该选项才能生效

    offset

    ①设置Tag指向的文本相对于基线的偏移距离

    ②可以控制文本相对于基线是升高(正数值)或者降低(负数值)

    ③默认值是0

    overstrike

    ①在Tag指定的文本范围画一条删除线

    ②默认值是False

    relief

    ①指定Tag对应范围的文本的边框样式

    ②可以使用的值有:SUNKEN,RAISED,GROOVE,RIDGE或FLAT

    ③默认值是FLAT(没有边框)

    margin

    ①设置Tag指向的文本块右侧的缩进

    ②默认值是0

    spacing1

    ①设置Tag所描述的文本块中每一行与上方的文本间隔

    ②注意:自动换行不算

    ③默认值是0

    spacing2

    ①设置Tag所描述的文本块中自动换行的各行间的空白间隔

    ②注意:换行符(" ")不算

    ③默认值是0

    spacing3

    ①设置Tag所描述的文本块中每一行与下方的文本间隔

    ②注意:自动换行不算

    ③默认值是0

    tabs

    ①定制Tag所描述的文本块中Tab按键的功能

    ②默认Tab被定义为8个字符的宽度

    ③你还可以定制多个制表位:tabs=('3c', '5c', '12c')表示前三个Tab的宽度分别为3cm,5cm,12cm,接着的Tab按照最后两个的差值计算,即:19cm,26cm,33cm

    ④你应该注意到,它上边'c'的含义是“厘米”而不是“字符”,还可以选择的单位有"i"(英寸),"m"(毫米),"p"(DPI,大约是'1i'等于'72p')

    ⑤如果是一个整型值,则单位是像素

    underline

    ①该选项设置为True的话,则Tag所描述的范围内的文本将被画上下划线

    ②默认值是False

    wrap

    ①设置当一行文本的长度超过width选项设置的宽度时,是否自动换行。

    ②该选项的值可以是:NONE(不自动换行),CHAR(按字符自动换行)和WORD(按单词自动换行)

    如果对于一个范围内容的文本加上多个Tags,并且相同的选项,那么新创建的Tag样式会覆盖比较旧的Tag:

    1 from tkinter import *
    2 root = Tk()
    3 text = Text(root,width=30,height=10)
    4 text.pack()
    5 text.tag_config("tag1",background="yellow",foreground="red")
    6 text.tag_config("tag2",foreground="blue")
    7 #tag2中foreground将覆盖tag1中的foreground,tag2中没有background,所以用tag1的
    8 text.insert(INSERT,'I love python3.6',("tag1","tag2"))
    9 mainloop()

    执行结果:

    不过,这里可以使用tagraise()和tag_lower()方法来提高和降低某个Tag的优先级:

    1 from tkinter import *
    2 root = Tk()
    3 text = Text(root,width=30,height=10)
    4 text.pack()
    5 text.tag_config("tag1",background="yellow",foreground="red")
    6 text.tag_config("tag2",foreground="blue")
    7 text.tag_lower("tag1")
    8 text.insert(INSERT,'I love python3.6',("tag1","tag2"))
    9 mainloop()

    执行结果:

    Tag还可以支持时间的绑定,绑定时间使用的是tag_bind()方法。下面举个例子:让文本(“python3.6”)与鼠标事件进行绑定,当鼠标进入该文本段的时候,鼠标样式切换“arrow”状态,离开文本段的时候切换回“xterm”形态。当触发鼠标“左键单击操作”时间的时候,使用默认浏览器打开绑定的链接:

     1 from tkinter import *
     2 root = Tk()
     3 text = Text(root,width=30,height=10)
     4 text.pack()
     5 text.insert(INSERT,'I love python3.6')
     6 text.tag_add("link","1.7","1.16")
     7 text.tag_config("link",foreground="blue",underline=True)
     8 def show_hand_cursor(event):
     9     text.config(cursor="arrow")
    10 def show_arrow_cursor(event):
    11     text.config(cursor="xterm")
    12 def click(event):
    13     webbrowser.open("http://www.baidu.com")
    14 text.tag_bind("link","<Enter>",show_hand_cursor)
    15 text.tag_bind("link","<Leave>",show_arrow_cursor)
    16 text.tag_bind("link","<Button-1>",click)
    17 mainloop()

    执行结果:

     下面给大家介绍几个比较实用的Text组件

    第一个是判断内容是否发生变化,例如做一个记事本,当用户关闭的时候,程序需要检查内容是否有改动,如果有,需要提醒用户保存。下面的例子中,可以通过小燕Text组件中文本的MD5摘要来判断内筒是否发生改变。

     1 from tkinter import *
     2 import hashlib
     3 root = Tk()
     4 text = Text(root,width=20,height=5)
     5 text.pack()
     6 text.insert(INSERT,"I love Python3.x")
     7 contents = text.get(1.0,END)
     8 def getSig(contents):
     9     m = hashlib.md5(contents.encode())
    10     return m.digest()
    11 sig = getSig(contents) 
    12 def check():
    13     contents = text.get(1.0,END)
    14     if sig != getSig(contents):
    15         print("内容没有保存")
    16     else:
    17         print("文件没有改动")
    18 Button(root,text="检查",command=check).pack()
    19 mainloop()

     执行结果:

    第二个是查找操作,是使用search()方法可以搜索Text组件中的内容,可以提供一个确切的目标进行搜索(默认),也可以使用Tcl格式的正则表达式进行搜索需要设置regexp选项为True(:):

     1 from tkinter import*
     2 root = Tk()
     3 text = Text(root,width=30,height=5)
     4 text.pack()
     5 text.insert(INSERT,"I love python3.6")
     6 #将任何格式的索引号统一为元组(行,列)的格式输出
     7 def getIndex(text,index):
     8     return tuple(map(int,str.split(text.index(index),".")))
     9 start = 1.0
    10 while True:
    11     pos = text.search("o",start,stopindex=END)
    12     if not pos:
    13         break
    14     print("找到了,位置是:",getIndex(text,pos))
    15     start = pos + "+1c" #将start指向下一个字符
    16 mainloop()

    执行结果:

    找到了,位置是: (1, 3)
    找到了,位置是: (1, 11)
    这里第一是找出“o"的位置,然后以"o"为起点,继续找第二个位置,直到找完
    注意:这里如果忽略stopindex选项,表示知道文本的末尾结束搜索。设置backwards选项为True,则是修改搜索的方向(变为向后搜索,那么start遍历应该设置为END,stopindex选项设置为1.0,最后+1c设置为-1c )
    最后,Text组件还支持“恢复”和“撤销”操作,这使得Text组件显得相当高大上。通过设置undo选项为True,可以开启Text组件的撤销功能,然后利用editundo可以开启实现撤销操作,用editredo()方法可以实现恢复操作。
     1 from tkinter import *
     2 import hashlib
     3 root = Tk()
     4 text = Text(root,width=20,height=5)
     5 text.pack()
     6 text.insert(INSERT,"I love Python3.x")
     7 def show():
     8     text.edit_undo()
     9 Button(root,text="撤销",command=show).pack()
    10 mainloop()
    执行结果:

    点击一次撤销后,插入进去的数据已经没有 了

    这是因为Text组件内部有一个栈专门用于记录每次变动,所以每次“撤销”操作就是一次弹栈操作,“恢复”就是再次压栈。

    默认情况下,每次完整的操作都会放入栈中。但怎么样算是一次完整的操作了?Tkinter觉得每次焦点切换、用户按下回车键、删除/插入操作的转换等之前的操作算是一次完整的操作。也就是说,你连续输入“python”的话,一次“撤销”操作就会将所有内容删除。

    但是我们可以自定义,做法就是先将autoseparators选项设置为False(因为这个选项是让Tkinter在人为一次完成的操作结束后自动插入“分隔符”,然后绑定键盘事件,每次有输入就用edit_separator()方法人为插入一个“分隔符”:

     1 from tkinter import *
     2 import hashlib
     3 root = Tk()
     4 text = Text(root,width=20,height=5,autoseparators=False,undo=True,maxundo=10) 5 text.pack()
     6 def callback():
     7     text.edit_separator()
     8 text.bind("<Key>",callback)
     9 text.insert(INSERT,"I love Python3.x")
    10 def show():
    11     text.edit_undo()
    12 Button(root,text="撤销",command=show).pack()
    13 mainloop()
    
    
  • 相关阅读:
    hdu2222 AC自动机入门
    bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
    【NOI2014】起床困难综合症 贪心
    bzoj1822: [JSOI2010]Frozen Nova 冷冻波网络流
    洛谷3767 膜法 带权并查集+分治
    NOI2015品酒大会 后缀数组
    NOI2015程序自动分析 并查集
    NOI2015软件包管理器 树剖线段树
    51nod1244 欧拉函数之和 杜教筛
    51nod1244 莫比乌斯函数之和 杜教筛
  • 原文地址:https://www.cnblogs.com/pinpin/p/9960779.html
Copyright © 2011-2022 走看看