绘制单行文本使用 Label 组件、多行选项使用 Listbox 组件、输入框使用 Entry 组件
显示和处理多行文本就需要使用我们的 Text 组件了。
Text 组件十分的强大和灵活,适用于多种任务。虽然说 Text 的主要目的是显示多行文本,但是也常常被当做简单的文本处理器、文本编辑器或者网页浏览器来使用。例如说我们的 IDLE 就是 Text 组件构成的。
目录
简单用法
插入图片和组件
插入按钮
插入图片
Indexs索引
line.column
line.end
INSERT
CURRENT
END(或"end")
user-defined marks
selection(SEL_FIRST, SEL_LAST)
window coordinate("@x,y")
embedded object name(window, images)
expressions
Marks用法
例一,Marks事实上就是索引,用于表示位置:
例二,如果Marks前边的内容发生变化,那么Mark的位置也会跟着移动(说白了就是Marks会记住它后边的那货):
例三,如果Marks周围的文本被删除了,Marks任然还在(只是它后面的那货被删除了,所以它六神无主,只能初始化为"1.0"):
例四,只有mark_unset()方法可以解除对Marks的封印:
Tags用法
设置样式
设置Tag优先级
事件绑定
下面来演示一下 Text 组件的用法:
from tkinter import *
root = Tk()
text = Text(root, width=30, height=2) #30的意思是30个平均字符的宽度,height设置为两行
text.pack()
text.insert(INSERT, 'I Love\n') #INSERT表示输入光标所在的位置,初始化后的输入光标默认在左上角
text.insert(END, 'Study!')
mainloop()
#生成好的Text组件可以进行编辑(并不是只读形式的)
Text 组件不仅支持编辑和插入文本,还支持插入图片和组件。
from tkinter import *
root = Tk()
text = Text(root, width=30, height=5)
text.pack()
text.insert(INSERT, 'I Love\n')
text.insert(END, 'Study!')
def show():
print('呦西,我被点了一下')
b1 = Button(text, text='点我', command=show) #注意放入的是Text而不是root了
text.window_create(INSERT, window=b1)
mainloop()
from tkinter import *
root = Tk()
text = Text(root, width=50, height=40)
text.pack()
photo = PhotoImage(file="D:\LOTUS专用图像\study.gif") #只支持GIF格式的
def show():
text.image_create(END, image=photo)
b1 = Button(text, text='点我', command=show) #注意放入的是Text而不是root了
text.window_create(INSERT, window=b1)
mainloop()
至于想要在 Text 组件中定位,就要使用到Indexs索引了。
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) | |
expressions |
由于 Text 支持多行文本,就是从一维空间变成了二维空间。因此可以用行和列定位一个位置。
那么,行列就是最基础的索引方式,他们将索引位置的行号和列号以字符串的形式表示出来(中间以"."分隔,例如"1.0"表示第一列第一行)。需要注意的是,行号以1开始,列号以0开始。你还可以使用以下语法构建索引:
"%d.%d" % (line, column)
指定超出现有文本的最后一行的行号,或超出一行中列数的列号都不会引发错误。对于这样的指定,Tkinter 解释为已有内容的末尾的下一个位置。
需要注意的是,使用行列的索引方式看起来像是浮点值。其实不只是像而已,你在需要指定索引的时候使用浮点值代替也是可以的:
text.insert(INSERT, 'I LOVE STUDY')
print(text.get('1.2', 1.6)) #1.2 1.6可以不加双引号
使用 index() 方法可以将所有支持的“索引”格式(上面写的那一大堆,11 个)转化为“行/列”格式的索引号
行号加上字符串 ".end" 的格式表示为该行最后一个字符的位置
text.insert(INSERT, 'I LOVE STUDY')
print(text.get('1.2', '1.end')) # end 为小写
#从第一行第三列到第一行最后
INSERT 和下面两个有点类似 C 的宏定义
INSERT (或 "insert" )
对应插入光标的位置
CURRENT (或 "current" ) --用的少
对应与鼠标坐标最接近的位置。不过,如果你紧按鼠标任何一个按钮,它会直到你松开它才响应(即你松开时的位置)
对应 Text 组件的文本缓冲区最后一个字符的下一个位置
user-defined marks 是对 Text 组件中位置的命名。INSERT 和 CURRENT 是两个预先命名好的 marks,除此之外你可以自定义 marks
User-defined tags 代表可以分配给 Text 组件的特殊事件绑定和风格。
你可以使用 "tag.first"(使用 tag 的文本的第一个字符之前)和 "tag.last"(使用 tag 的文本的最后一个字符之后)语法表示标签的范围。
"%s.first" % tagname
"%s.last" % tagname
如果查无此 tag,那么 Tkinter 会抛出 TclError 异常
selection 是一个名为 SEL(或 "sel" )的特殊 tag,表示当前被选中的范围,你可以使用 SEL_FIRST 到 SEL_LAST 来表示这个范围,如果没有选中的内容,那么 Tkinter 会抛出 TclError 异常
你还可以使用窗口坐标作为索引。例如在一个事件绑定中,你可以使用以下代码找到最接近鼠标位置的字符:
"@%d,%d" % (event.x, event.y)
embedded object name 用于指向在 Text 组件中嵌入的 window 和 image 对象。要引用一个 window,只要简单的将一个 Tkinter 组件实例作为索引即可。引用一个嵌入的 image,只需使用相应的 PhotoImage 和 BitmapImage 对象
expressions 用于修改任何格式的索引,用字符号的形式实现修改索引的表达式。
具体表达式实现如下:
表达式 | 含义 |
---|---|
+ count chars | ①将索引向前(->)移动count个字符 ②可以越过换行符,但不能超过END的位置 |
- count chars | ①将索引向后(<-)移动count个字符 ②可以越过换行符,但不能超过"1.0"的位置 |
+ count lines | ①将索引向前(->)移动count行 ②索引会尽量保持与移动前在同一列上,但如果移动后的那一行字符太少,将移动到该行的末尾 |
- count lines | ①将索引向后(<-)移动count行 ②索引会尽量保持与移动前在同一列上,但如果移动后的那一行字符太少,将移动到该行的末尾 |
linestart | ①将索引移动到当前索引所在行的起始位置 ②注意,使用该表达式前边必须有一个空格隔开 |
lineend | ①将索引移动到当前索引所在行的末尾 ②注意,使用该表达式前边必须有一个空格隔开 |
wordstart | ①将索引移动到当前索引指向的单词的开头 ②单词的定义是一系列字母、数字、下划线或任何非空白字符的组合 ③注意,使用该该表达式前边必须有一个空格隔开 |
wordend | ①将索引移动到当前索引指向的单词的末尾 ②单词的定义是一系列字母、数字、下划线或任何非空白字符的组合 ③注意,使用该该表达式前边必须有一个空格隔开 |
ps.只要结果不产生歧义,关键字可以被缩写,空格也可以省略。例如:"+ 5 chars" 可以简写成 "+5c"
在实现中,为了确保表达式为普通字符串,你可以使用 str 或格式化操作来创建一个表达式字符串。下面例子演示了如何删除插入光标前边的一个字符:
def backspace(event):
event.widget.delete("%s-1c" % INSERT, INSERT)
如果看书时发现一句美句,拿出笔和本,在本上写下这句话的位置(这是 Marks),并在书上对美句画横线(这是 tag)。
Marks(标记)通常是嵌入到 Text 组件文本中的不可见对象。事实上 Marks 是指定字符串间的位置,并跟随相应的字符一起移动。Marks 有 INSERT,CURRENT 和 user-defined marks(用户自定义 Marks)。其中,INSERT 和 CURRENT 是 Tkinter 预定义的特殊 Marks,他们不能被删除。
INSERT(或 "insert") 用于指定当前插入光标的位置,Tkinter 会在该位置绘制一个闪烁的光标(因此,并不是所有的 Marks 都不可见)
CURRENT(或 "current")用于指定对应与鼠标坐标最接近的位置。不过,如果你紧按鼠标任何一个按钮,它会直到你松开它才响应(即你松开时的位置)
你还可以自定义任意数量的 Marks,Marks 的名字是由普通字符串组成,可以是除了空白字符外的任何字符(为了避免歧义,你应该起一个有意义的名字)。使用 mark_set() 方法创建和移动 Marks。
如果你在一个 Mark 标记的位置之前插入或删除文本,那么 Marks 会跟着一起移动。删除 Marks 你需要使用 mark.unset() 方法,删除 Marks 周围的文本并不会删除 Marks 本身
text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2') #第一行第三列做一个标记
text.insert('here', '插') #利用标记插入字符串
#原来的字符串变成'I 插love study'
text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.insert('here', '插')
text.insert('here', '入')
#原来的字符串变成'I 插入love study'
text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.insert('here', '插')
text.delete('1.0', 'end')
text.insert('here', '入')
#原来的字符串变成'入'
text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.insert('here', '插')
text.mark_unset('here')
text.delete('1.0', 'end')
text.insert('here', '入')
#会报TclError的错误
默认插入内容到 Marks,是插入到它的左边(就是说插入一个字符的话,Marks 向后移动了一个字符的位置)。
那能不能插入到 Marks 的右侧呢(即 Marks 的位置一直不变)?其实是可以的,通过 mark_gravity() 方法就可以实现:
text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.mark_gravity('here', LEFT) #默认是RIGHT,也就是说插入一个数据,Marks默认是在这个数据的右边,即可能会(插入数据在Marks的右边时)相对插入前Marks的位置移动了一个。
text.insert('here', '插')
text.insert('here', '入')
#结果是"I 入插love study"
不难总结出,Index 索引和 Marks 标记都是主要用于定位。Marks 可以看做是特殊的 Index,是一个可以自定义名字的 Index。但是他们又不是完全相同的,比如说在默认的情况下,在 Marks 指定的位置中插入数据,Marks 的位置会自动发生改变。
Tags(标签)通常用于改变 Text 组件中内容的样式和功能。你可以修改文本的字体、尺寸和颜色。另外,Tags 还允许你将文本、嵌入的组件和图片与鼠标和键盘等事件相关联。除了 user-defined tags(用户自定义的 Tags),还有一个预定义的特殊Tags:SEL。
SEL (或 "sel")用于表示对应的选中内容(如果有的话)。
可以自定义任意数量的 Tags,Tags 的名字是由普通字符串组成,可以是除了空白字符以外的任何字符。另外,任何文本内容都支持多个 Tags 描述,任何 Tag 也可以用于描述多个不同的文本内容。
为指定文本添加 Tags 可以使用 tag_add() 方法:
text.insert(INSERT, 'I love study very well')
text.tag_add('tag1', '1.7', '1.12', '1.14') #第一个参数是tag的名字,之后的参数是范围。这些参数表示的范围是'1.7'到'1.12'和一个单独的'1.14'
#光是这样只是在指定位置标注了一个tag标签,还需要对这些标签进行设置
text.tag_config('tag1', background='yellow', foreground='red')
#字符串'I love study very well'中'study'和'e'颜色改变
如上,使用 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所描述的文本块中自动换行的各行间的空白间隔 ②注意:换行符("\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(按单词自动换行) |
如果你对同一个范围内的文本加上多个 Tags(会形成一个栈的形式),并且设置相同的选项,那么新建的 Tag 样式会覆盖比较旧的 Tag:
from tkinter import *
root = Tk()
text = Text(root, width=30, height=5)
text.pack()
text.insert(INSERT, 'I love study very well')
text.tag_add('tag1', '1.7', '1.12', '1.14')
text.tag_add('tag2', '1.7', '1.12', '1.14')
#注意这里是创建的顺序起决定性的作用
text.tag_config('tag2', foreground='blue')
text.tag_config('tag1', background='yellow', foreground='red')
#最后的前景色是蓝色,背景色还是黄色
mainloop()
这里的前景蓝色有点不那么显眼,仔细看是蓝色的。
你或许想控制 Tags 间的优先级,这可以实现么?
你可以使用 tag_raised() 和 tag_lower() 方法来提高和降低某个 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的顺序
#到这里是黄底红字的
text.tag_lower('tag1')
#到这里就成了黄底蓝字
text.insert(INSERT, 'I love study very well', ('tag2', 'tag1')) #和这里的tag选项的顺序无关。这样Tag加入的是整个文本
mainloop()
另外 Tags 还支持事件绑定,使用的是 tag_bind() 的方法。
下边的例子中,我们将文本("Baidu.com")与鼠标事件进行绑定,当鼠标进入该文本段时,鼠标样式切换为 "arrow" 形态,离开文本段的时候切换回 "xterm" 形态。当触发鼠标“左键点击操作”时,使用默认浏览器打开百度首页
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):
text.config(cursor='arrow')
def show_xterm_cursor(event):
text.config(cursor='xterm')
def click(event):
webbrowser.open('http://www.baidu.com')
text.tag_bind('link', '', show_arrow_cursor) #指的是当鼠标进入的时候调用show_hand_cursor函数
text.tag_bind('link', '', show_xterm_cursor)
text.tag_bind('link', '', click)
mainloop()