python基础学习-tkinter(四)

Text文本控件

Text 文本控件,用于显示多行文本。但是也常常被当做简单的文本处理器、文本编辑器或者网页浏览器来使用。例如说我们的 IDLE 就是 Text 组件构成的。
简单的一个应用:

from tkinter import *

root = Tk()
text = Text(root,width=30,height=4)
text.pack()
# INSERT表示输入光标所在的位置,初始化后的输入光标默认在左上角
text.insert(INSERT,'I LOVE \n')
text.insert(END,'TOUDA')
mainloop()

输出:
在这里插入图片描述

生成好的Text组件可以进行编辑(并不是只读形式的)

插入图片

Text组件不仅支持文本也支持图片

from tkinter import *

root = Tk()
text = Text(root,width=90,height=40)
text.pack()

photo = PhotoImage(file='1.gif') #只支持GIF格式的

def show():
    text.image_create(END,image=photo)
    print("点击一下!!!")

b1 = Button(text,text='点击',command=show)
text.window_create(INSERT,window=b1)

mainloop()

输出:
在这里插入图片描述

Indesx索引

Indexs(索引是用来指向 Text 组件中文本的位置,跟 Python 的序列索引一样,Text 组件索引也是对应实际字符之间的位置。
Tkinter 提供一系列不同的索引类型:

索引类型
line.column 行/列
line.end 某一行的末尾
INSERT
CURRENT
END
user-defined marks
user-defined tags(“tag.first”, “tag.last”)
selection(SEL_FIRST, SEL_LAST)
window coordinate("@x,y")
embedded object name(window, images)

line.column
行列就是最基础的索引方式,他们将索引位置的行号和列号以字符串的形式表示出来(中间以"."分隔,例如"1.0"表示第一列第一行)。需要注意的是,行号以1开始,列号以0开始

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

INSERT
INSERT (或 “insert” )对应插入光标的位置

CURRENT (或 “current” )
对应与鼠标坐标最接近的位置。不过,如果你紧按鼠标任何一个按钮,它会直到你松开它才响应(即你松开时的位置)

END(或"end")
对应 Text 组件的文本缓冲区最后一个字符的下一个位置

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

User-defined tags(“tag.first”, “tag.last”)
User-defined tags 代表可以分配给 Text 组件的特殊事件绑定和风格。
你可以使用 “tag.first”(使用 tag 的文本的第一个字符之前)和"tag.last"(使用 tag 的文本的最后一个字符之后)语法表示标签的范围。
如果查无此 tag,那么 Tkinter 会抛出 TclError 异常

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

window coordinate("@x,y")
你还可以使用窗口坐标作为索引。例如在一个事件绑定中,你可以使用以下代码找到最接近鼠标位置的字符:

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

expressions
expressions 用于修改任何格式的索引,用字符号的形式实现修改索引的表达式。

具体表达式实现如下:

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

在不产生歧义,关键字可以被缩写,空格也可以省略,例如:"+ 5 chars" 可以简写成 “+5c”

Marks用法
Marks(标记)通常是嵌入到 Text 组件文本中的不可见对象。事实上 Marks 是指定字符串间的位置,并跟随相应的字符一起移动。Marks 有 INSERT,CURRENT 和 user-defined marks(用户自定义 Marks)。其中,INSERT 和 CURRENT 是 Tkinter 预定义的特殊 Marks,他们不能被删除。
可以自定义任意数量的 Marks,Marks 的名字是由普通字符串组成,可以是除了空白字符外的任何字符(为了避免歧义,你应该起一个有意义的名字)。使用 mark_set() 方法创建和移动 Marks。
下面看一个程序:

from tkinter import *
root = Tk()

text = Text(root,width=50,height=4)
text.pack()

text.insert(INSERT,'I love fishc.com')
# 行数从1开始,列从0开始,'here'在这里就是标记的意思,下面就是利用这个标记插入
text.mark_set('here','1.2')
# 随着前面的内容的变化,Marks位置也在跟着变化
text.insert('here','入')
# 将Marks周围的文本删除
# text.delete('1.0','end')
# 默认插入到 Marks 的右侧,通过mark_gravity可以设置为左边
text.mark_gravity('here',LEFT)
text.insert('here','插')
# 通过mark_unset()解除对 Marks的封印
text.mark_unset('here')

mainloop()

输出:

I 入插love fishc.com

Tags用法

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

选项 含义
background ①指定该Tag所描述的内容的背景颜色②注意:bg并不是该选项的缩写,在这里bg被解释成bgstipple选项的缩写
bgstipple ①指定一个位图作为背景,并使用background选项指定的颜色填充②只有设定了background选项,该选项才会生效
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所描述的文本块中自动换行的各行间的空白间隔②注意:换行符("\n")不算③默认值是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(按单词自动换行)

Tag有优先级,在设置同一个范围时,新建的Tag样式会覆盖旧的Tag,可以通过设置优先级来显示,下面通过一个程序说明:

from tkinter import *

root = Tk()

text = Text(root, width=30, height=5)
text.pack()

text.tag_config('tag2', foreground='blue')  # 设置tag的选项时,如果没有该tag,则会新建一个
text.tag_config('tag1', background='yellow', foreground='red')  # 此时这个就是新建的Tag的顺序
# 设置tag1为低优先级
text.tag_lower('tag1')
text.insert(INSERT, 'I love study very well', ('tag2', 'tag1'))  # 和这里的tag选项的顺序无关。这样Tag加入的是整个文本

mainloop()

输出:

在这里插入图片描述
Tag还可以与事件绑定,使用tag_bind()方法。
下面我们将文本(“Baidu.com”)与鼠标事件进行绑定,当鼠标进入该文本段时,鼠标样式切换为 “arrow” 形态,离开文本段的时候切换回 “xterm” 形态。当触发鼠标“左键点击操作”时,使用默认浏览器打开百度首页
在程序中加入print(“a”),print(“b”)为调试方便设置的。

from tkinter import *
import webbrowser

root = Tk()

text = Text(root,width=30,height=5)
text.pack()

text.insert(INSERT,"Baidu.com的创始人是李彦宏")
text.tag_add('link','1.0','1.8')
text.tag_config('link',foreground='blue',underline='True')
def show_arrow_cursor(event):
    print("a")
    text.config(cursor='arrow')

def show_xterm_cursor(event):
    print("b")
    text.config(cursor='xterm')

def click(event):
    print("c")
    webbrowser.open("http://www.baidu.com")

text.tag_bind('link','<Enter>',show_arrow_cursor)
text.tag_bind('link','<Leave>',show_xterm_cursor)
text.tag_bind('link','<Button-1>',click)

mainloop()

输出:
每当鼠标移动"Baidu.com"输出"a",离开时输出"b",点击时,进入百度网页。
在这里插入图片描述

Text组件的使用技巧

判断内容是否发生变化

应用背景:比如说做一个笔记本 (.txt 的那个记事本) 程序,或者重新做一个 IDLE。它们都有输入框,有输入框当程序在关闭的时候应该自动检测内容是否发生改变,如果有改变但用户并没有保存的时候,应该提醒用户是否保存。

我们这个例子是通过验证文本的 md5 摘要来判断文本是否发生改变。

from tkinter import *
import hashlib

root = Tk()

text = Text(root,width=30,height=5)
text.pack()

text.insert(INSERT,'头疼头大!')
contents = text.get("1.0",END)

def getSig(contents):
    n = hashlib.md5(contents.encode())
    return n.digest()

sig = getSig(contents)
def check():
    contents = text.get("1.0",END)
    if sig != getSig(contents):
        # 这里为了方便调试,看看sig输出到底是什么
        print(sig)
        print(getSig(contents))
        print("内容改变了!!!")
    else:
        print("没有改变!!!")

Button(root,text="检查",command=check).pack()

mainloop()

输出:
在这里插入图片描述

查找操作

查找使用 search 方法,使用 search 方法可以对 text 的内容进行搜索。

不过默认是只找到第一个位置。下面是一个可以全文搜索数字的例子:

from tkinter import *
import hashlib

root = Tk()

text = Text(root,width=30,height=5)
text.pack()

text.insert(INSERT,'12345678 8452125823')

def getIndex(text,index):
    # 调试用的
    # print(str.split(text.index(index),"."))
    # print(map(int,str.split(text.index(index), ".")))
    return tuple(map(int,str.split(text.index(index),'.')))
start = '1.0'
while True:
    pos = text.search("3",start,stopindex=END)
    print(pos)
    if not pos:
        break
    print("找到了,位置是:",getIndex(text,pos))
    start = pos + "+1c"
mainloop()

输出:
在这里插入图片描述

Text组件还支持恢复和撤销的操作

我们可以简单设置 Text 组件的 undo 选项为 True 开启其撤销功能,然后使用 edit_undo() 方法来实现撤销操作,用 edit_redo() 的方法来实现其恢复操作。

from tkinter import *
root = Tk()

text = Text(root,width=30,height=5,undo=True)
text.pack()

text.insert(INSERT,"I enjoy studying Python")

def show():
    text.edit_undo()

Button(root,text="撤销",command=show).pack()

mainloop()

输出:
在这里插入图片描述
这是因为 Text 组件内部有一个栈专门用于记录内容的每次变动,所以每次撤销操作就是一次弹栈操作,恢复就是再次压栈。

默认情况下,每一次完整操作将会放入栈中但怎么样才算是一次完整的操作呢?Tkinter 觉得每次焦点切换,用户按下 Enter 键。删除\插入操作的转换等之前的操作算是一次完整的操作。

自定义撤销操作

那我们能不能自定义呢?比如说我希望插入一个字符就算一次完整的操作,然后每次点击撤销就去掉一个字符。

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

from tkinter import *

root = Tk()
text = Text(root,width=30,height=5,undo=True,autoseparators=False)
text.pack()

text.insert(INSERT,"头大头疼呀!")

def callback(event):
    text.edit_separator()

text.bind('<Key>',callback)
def show():
    text.edit_undo()
Button(root,text="撤销",command=show).pack()

mainloop()

输出:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42711815/article/details/88852471