GUI的终极选择:Tkinter7:Text(2)

##Text
   (Text组件的Indexs 索引和 Marks 标记,它们主要是用于定位,Marks 可以看做是特殊的 Indexs,但是它们又不是完全相同的,比如在默认情况下,你在Marks指定的位置中插入数据,Marks 的位置会自动发生改变,因为Marks 认它后面的“那个家伙”,当 Marks 前面的数据被删除时,Marks 并不会被删除,它的位置只是相应的向前移动了,因为Marks 只认它后面的“那个家伙”,然后只有 mark_unset() 方法 才能够删除Marks)

   Tags 用法:

   Tags(标签)通常用于改变 Text 组件中内容的样式和功能。你可以修改文本的字体、尺寸和颜色。另外,Tags 还允许你将文本、嵌入的组件(例如Button)和图片与键盘和鼠标等事件相关联。除了 user-defined tags(用户自定义的 Tags),还有一个预定义的特殊 Tag:SEL。   (与鼠标事件进行关联比如说,baidu.com是个域名,我们就可以关联鼠标操作,当鼠标上去的时候,会变成一个小手指,然后点击的时候,就会弹出百度首页)

   SEL(或 “sel”)用于表示对应的选中内容(如果有的话)。

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

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

from tkinter import *


root = Tk()

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

text.insert(INSERT,"I love Dogdog.com")


text.tag_add("tag1","1.7","1.12","1.14")
text.tag_config("tag1",background = "yellow",foreground = "red")

    
root.mainloop()

在这里插入图片描述
在这里插入图片描述
(解析:首先实例化好Text组件和插入相应内容后,然后用text对象的tag_add方法来添加一个标签,第一个参数就是标签的名字,之后的参数就是你的范围,例如说这里是1.7,第一行的第八列,因为列是从0开始的,就是D,然后到哪里就是接下去的参数,这里是1.12,第一行的13列,然后再来一个单独的,1.14就是第一行15列,到这里,他只是说在这个指定的位置标注了一个tag标签,但我们还没有对这个标签进行一个设置,可以通过tag_config这个方法来设置标签的样式,什么左对齐,右对齐,缩进都是可以调整的,这里就设置背景色和前景色,这里bg的缩写不是表示背景色,而是表示bgstipple,指定一个位图作为背景,并使用 background 选项指定的颜色填充,在其他组件bg都是background的缩写,知道就好)

   还有一点需要注意的是:如果你对同一个范围内的文本加上多个 Tags,并且设置相同的选项,那么新创建的 Tag 样式会覆盖比较旧的 Tag:(事实上,对同一个文本创建tag,他会形成一个tag的栈,一个栈的数据结构,那么他新进去的就会覆盖旧的)

from tkinter import *


root = Tk()

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

text.insert(INSERT,"I love Dogdog.com")


text.tag_add("tag1","1.7","1.12","1.14")
text.tag_add("tag2","1.7","1.12","1.14")
text.tag_config("tag1",background = "yellow",foreground = "red")#旧的Tag
text.tag_config("tag2",foreground = "white",) #新的Tag

# 那么新创建的 Tag2 会覆盖比较旧的 Tag1 的相同选项
    
root.mainloop()

在这里插入图片描述
(解析:如上,新创建的tag2,只设置了前景色为白色,然后把这个tag2标签放到了和tag1标签一样的位置,指定同一段文本,通过结果截图可以看到,tag2白色的前景色覆盖了tag1红色的前景色,因为旧的创建在栈低,新的在栈顶,所以直接用新的了,然后可以发现,背景颜色没有发生改变,因为这里没有覆盖到他的背景色,所以依旧用tag1的背景颜色)

   你或许想控制 Tags 间的优先级,这可以实现吗?完全没有问题!你可以使用 tag_raise()tag_lower() 方法来提高和降低某个 Tag 的优先级。

from tkinter import *


root = Tk()

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

text.tag_config("tag1", background="yellow", foreground="red")
text.tag_config("tag2", foreground="white")

#降低tag2的优先级 
text.tag_lower("tag2")

# 注意,与下边的调用顺序没有关系
text.insert(INSERT, "I love Dogdog.com", ("tag2", "tag1"))

root.mainloop()

在这里插入图片描述

   另外 Tags 还支持事件绑定,使用的是 tag_bind() 的方法。

   下边例子中我们将文本(“baidu.com”)与鼠标事件进行绑定,当鼠标进入该文本段的时候,鼠标样式切换为 “arrow” 形态(小手的样子),离开文本段的时候切换回 “xterm” 形态。当触发鼠标“左键点击操作”事件的时候,使用默认浏览器打开百度的首页(https://www.baidu.com):

from tkinter import *
import webbrowser


root = Tk()

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



text.insert(INSERT,"I love baidu.com")


text.tag_add("link","1.7","1.16")
text.tag_config("link",foreground = "blue",underline = True)

def show_arrow_cursor(event):
    text.config(cursor="hand2") #arrow

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

def click(event):
    webbrowser.open("https://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)


root.mainloop()

在这里插入图片描述
在这里插入图片描述
   (解析:首先给文本中的域名加上标签text.tag_add(“link”,“1.7”,“1.16”)同时设置背景色为蓝色text.tag_config(“link”,foreground = “blue”,underline = True),然后这里超链接加个下划线比较好看,所以再加上那个underline选项,他是布尔类型的值,给个True就会显示下划线了

   接下来来做一个事件绑定,事件绑定的知识在后边的章节会有讲解,这里先来熟悉一下,绑定事件使用的是tag_bind方法,text.tag_bind(“link”,"<Enter>",show_arrow_cursor),这里第一个参数就是绑定的是link这个标签,而这个标签又是标记那个域名的,第二个参数表示当鼠标进入的时候,即事件,然后第三个参数在写个command回调函数,当鼠标进入的时候就调用这个函数,函数名可以自己定,但最好有意义,在这个函数函数里, text.config(cursor=“hand2”) ,事实上就是设置cursor他的鼠标(各个组件都有设置他的cursor这么一个选项)设置为hand2,就是变成小手的样子

   接着在写一个绑定事件text.tag_bind(“link”,"<Leave>",show_xterm_cursor),就是当鼠标离开这个链接的的时候,鼠标就变成大写字母I的亚子,接着还需要单击事件,ext.tag_bind(“link”,"<Button-1>",click),就是点击了超链接部分就会跳转到百度首页面,那三个回调函数都需要一个event参数,

   然后跳转打开网页需要一个webbrowser模块,所以需要导入,webbrowse主要是一个用于打开网页的一个成熟的模块,我们直接使用这个默认的模块就可以了,同样是open方法,然后参数就是要打开的网址)

   下面介绍几个非常实用的Tags 使用上的技巧:

   (一)通过校检 Text 组件中文本的 MD5 摘要来判断内容是否发生改变
   (比如说你这个笔记本程序,或者说你重新写个IDLE,都可以,你都有输入框,那么有输入框,当用户在关闭的时候,程序应该自动检测内容是否发生改变,如果有改变,而用户忘记保存了,这时我们就应该给出提示善意地提醒是否要保存)

from tkinter import *
import hashlib


root = Tk()

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


text.insert(INSERT,"I love baidu.com")
contents = text.get("1.0",END)   #原始内容

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

sig = getSig(contents)     #获取原始内容的

def check():
    contents = text.get("1.0",END)
    if sig != getSig(contents):
        print("警报:内容发生变动!")
    else:
        print("风平浪静~~")
    
    
Button(root,text = "检查",command = check).pack()

root.mainloop()

在这里插入图片描述                              在这里插入图片描述
   (解析:首先他的实现原理就是:先获取原始的内容,然后将原始的内容进行一个md5的hash获得他的md5的值,然后点击按钮后,触发相应的函数再一次获取内容,同时获取它对应md5的值,再来和原始内容获取的md5的值作比较就可以了,因为一个内容只能产生一个唯一的散列,不一样就说明内容发生了改变

   那么这里就是contents = text.get(“1.0”,END) 先获取了原始内容,然后下面封装了一个获取md5值的方法,只需要传入内容就可以返回对应md5的值,获取了原始内容就调用getSig得到sig,然后这个函数里边获取md5的值需要用到一个hashlib的模块,m = hashlib.md5(contents.encode()),这里需要进行一个二进制编码,然后获取md5的值,获得之后就在这个m里边,返回m.digest,获得他的摘要,我们只要得到一个简单的摘要的值就可以了,然后匹配摘要看是否一样,一样就没有变动)

   (二)使用 search() 方法可以搜索 Text 组件中的内容。但是传统的 search() 方法只查找到一个,就返回,我们可以加入一个循环,查找所有的内容。

from tkinter import *


root = Tk()

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


text.insert(INSERT,"I love baidu.com")


def getIndex(text, index):
    return tuple(map(int, str.split(text.index(index), ".")))
 
start = 1.0
while True:
    pos = text.search("o", start, stopindex=END)
    if not pos:
        break
    print("找到啦,位置是:", getIndex(text, pos))
    start = pos + "+1c"  # 将 start 指向下一个字符

root.mainloop()

在这里插入图片描述
   (解析:start = 1.0,首先定义开始开始的位置,即第一行第0列, pos = text.search(“o”, start, stopindex=END),然后在循环里用text对象的search方法,第一个参数就是要找的内容,第二个参数就从哪里开始,第三个参数就是到哪里结束,就是从1.0搜索到文本最后,如果没有找到就直接break,跳出循环即可,否则的话就打印,这里封装个把pos转化成人类能够读懂的位置,上一章讲了用text的index方法可以把任何支持的格式转化为默认的行列字符串的格式,然后这里希望转化后变成元组返回, 打印出一个位置后,就需要发生变动,位置进行一个改变,指向下一个位置:start = pos + "+1c"即将 start 指向下一个字符)

   (二)Text 组件还支持“恢复”和“撤销”操作,这使得 Text 组件显得相当高大上。只需要简单地设置undo = True(默认是False)就开启Text组件的撤销功能,然后调用对应方法来实现即可   (就是如果你输错一段文本可以点撤销,或者说不小心删除一个文本,也可以撤销删除操作,)

from tkinter import *

root = Tk()

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


text.insert(INSERT,"I love baidu.com")


def show():
    text.edit_undo()

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

root.mainloop()

在这里插入图片描述                  在这里插入图片描述在这里插入图片描述                  在这里插入图片描述
   (解析:首先在初始化Text组件时加上undo选项,设置为Ture,因为他默认是False,开启后再加个Button来测试,当点击按钮后,执行触发command绑定的show函数,text.edit_undo(),show函数里边就调用了edit_undo方法就可以了,这里要注意的是,如果undo没打开的话,这里就不会有响应,要打它这个功能才可以,可以看到把后面的删除了,点撤销,他又会出现了,在撤销就会全部都没了,把插入操作也撤销完了,再点撤销就会抛出异常,因为没东西可以撤销了)

   其实他的原理就是Text 组件内部有一个栈专门用于记录内容的每次变动,所以每次“撤销”操作就是一次弹栈操作,“恢复”就是再次压栈。   (意思就是说,当你开启这个undo为True的话,他就会有一个栈,你每一次操作他都会记住,记录在栈中,每一次进行撤销操作,就会从栈顶弹出然后把他恢复

   默认情况下,每一次完整的操作将会放入栈中。但怎么样算是一次完整的操作呢?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,"I love baidu.com")

def callback(envent):
    text.edit_separator() #人为地插入分割符

#<Key>表示键盘事件,下面表示绑定了一个键盘事件,
#就是每次输入的时候就触发callback函数加一个分割符
text.bind("<Key>",callback)


def show():
    text.edit_undo()

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

root.mainloop()

在这里插入图片描述                  在这里插入图片描述
在这里插入图片描述                  在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值