/***************************/
使用from tkinter import *
添加组件时可以不用加tk.
/***************************/



示例代码1
#encoding=utf-8
import tkinter as tk         #导入tkinter模块

app = tk.Tk()                #注意大写T小写k
#定义Toplevel级别(root)窗口

app.title("Fishc Demo")      #标题

theLabel = tk.Label(app, text="我的第一个窗口程序！")#标签
theLabel.pack()              #自动调节组件的尺寸

app.mainloop()               #GUI程序最后一段代码，主事件循环


基本步骤：
1.定义窗口
app=tk.Tk()
2.写标题
app.title("标题")
3.标签
theLabel=tk.Label(app, text="标签")  #表示在app窗口上添加一个标签
4.组件尺寸
theLabel1.pack()             #表示标签组件的默认尺寸
5.结束构建
app.mainloop()               #GUI程序最后一段代码，主事件循环




示例代码2
import tkinter as tk

class APP:
	def __init__(self,master):
		frame=tk.Frame(master)
		frame.pack(side=tk.LEFT,padx=10,pady=10)

		self.hi_there = tk.Button(frame, text="打招呼",fg="white",bg="black",command=self.say_hi)
		self.hi_there.pack()

	def say_hi(self):
		print("你好！我是你的第一个程序")

root = tk.Tk()
app = APP(root)

root.mainloop()


基本步骤：
1.声明类，对窗口进行设置
初始化参数为master
2.将tk.Frame(master)实例化为frame，表示设置框架组件
3.设置框架组件尺寸及位置
pack(side=ti.[LEFT,RIGHT,TOP,BOTTOM]表示从什么方向开始走起，padx=n(x轴开始几个像素)，pady=n(y轴开始几个像素))
4.按钮设置
tk.Button(frame, text="打招呼",fg="white",bg="black",command=self.say_hi)
tk.按钮组件(在frame框架中添加名为"打招呼"的按钮，前景色填充为白色，背景色填充为黑色，单击时触发say_hi)



/**********************************/
鱼c笔记——Python的GUI编程（六）：Tkinter的Text组件
#Text

绘制单行文本使用Label组件

多行选项使用Listbox组件

输入框使用Entry组件

显示和处理多行文本就需要使用我们的Text组件了。



但是Text组件十分的强大和灵活适用于多种任务，虽然说Text的主要目的是显示多行文本，但是也常常被当做简单的文本处理器、文本编辑器或者网页浏览器来使用。例如说我们的IDLE就是Text组件构成的。



下面来演示一下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



"line.column"

由于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个）转化为“行/列”格式的索引号






"line.end"

行号加上字符串".end"的格式表示为该行最后一个字符的位置

text.insert(INSERT, 'I LOVE STUDY')
print(text.get('1.2', '1.END'))
#从第一行第三列到第一行最后


INSERT和下面两个有点类似C的宏定义

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的文本的最后一个字符之后）语法表示标签的范围。

"%s.first" % tagname
"%s.last" % tagname
如果查无此tag，那么Tkinter会抛出TclError异常



selection(SEL_FIRST, SEL_LAST)

selection是一个名为SEL（或"sel" ）的特殊tag，表示当前被选中的范围，你可以使用SEL_FIRST到SEL_LAST来表示这个范围，如果没有选中的内容，那么Tkinter会抛出TclError异常



window coordinate("@x,y")

你还可以使用窗口坐标作为索引。例如在一个事件绑定中，你可以使用以下代码找到最接近鼠标位置的字符：

"@%d,%d" % (event.x, event.y)


embedded object name(window, images)

embedded object name用于指向在Text组件中嵌入的window和image对象。要引用一个window，只要简单的将一个Tkinter组件实例作为索引即可。引用一个嵌入的image，只需使用相应的PhotoImage和BitmapImage对象



expressions

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用法

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本身



例一，Marks事实上就是索引，用于表示位置：

text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2') #第一行第三列做一个标记
text.insert('here', '插') #利用标记插入字符串
 
#原来的字符串变成'I 插love study'

例二，如果Marks前边的内容发生变化，那么Mark的位置也会跟着移动（说白了就是Marks会记住它后边的那货）：

text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.insert('here', '插')
text.insert('here', '入')
 
#原来的字符串变成'I 插入love study'

例三，如果Marks周围的文本被删除了，Marks任然还在（只是它后面的那货被删除了，所以它六神无主，只能初始化为"1.0"）：

text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.insert('here', '插')
 
test.delete('1.0', END)
text.insert('here', '入')
 
#原来的字符串变成'入'

例四，只有mark_unset()方法可以解除对Marks的封印：

text.insert(INSERT, 'I love study')
text.mark_set('here', '1.2')
text.insert('here', '插')
 
text.mark_unset('here')
 
test.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用法

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', '<Enter>', show_arrow_cursor)  #<Enter>指的是当鼠标进入的时候调用show_hand_cursor函数
text.tag_bind('link', '<Leave>', show_xterm_cursor)
text.tag_bind('link', '<Button-1>', click)
 
mainloop()

/******************************/
鱼c笔记——Python的GUI编程（四）：Tkinter组件Entry
#Entry
内容概要：

Entry组件的基本用法

Entry的show, width属性

Entry的验证功能

Label组件的row, column属性

Button组件的sticky属性





Entry组件：输入框

输入框是和程序打交道的一个途径。比如说程序要求输入账号和密码，就需要提供两个输入框，接受密码的输入框还会用*星号将实际内容隐藏起来。

学了好几个Tkinter的组件，不难发现，很多方法和选项之间是通用的，意思是名字一样，内容也一样。比如说，在输入框中用代码增加和删除内容，就是使用insert()和delete()方法。



from tkinter import *
 
root = Tk()
 
e = Entry(root)
e.pack(padx=20, pady=20)
 
e.delete(0, END)  #将输入框里面的内容清空
e.insert(0, '默认文本在此！')
 
mainloop()

获取数据框里的内容，可以使用Entry组件里的get方法。也可以将Tkinter的变量，通常是字符串类型的变量挂钩到textvariable选项上，再通过变量的get方法获取也是可以的。

#tkinter提供了三种布局组件的方式，第一种是pack()，第二种是Grid()网格，第三种是prase()
#Grid允许我们使用表格的形式管理组件
from tkinter import *
 
root = Tk()
 
Label(root, text='作品：').grid(row=0, column=0)  #选项row代表行，column代表列
Label(root, text='作者：').grid(row=1, column=0)
 
 
e1 = Entry(root)
e2 = Entry(root)
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)
 
def show():
    print("作品：《%s》" % e1.get())
    print("作者：%s" % e2.get())
 
Button(root, text='获取信息', width=10, command=show)\
             .grid(row=3, column=0, sticky=W, padx=10, pady=5) #sticky参数的值和anceror的一样，用来设置按钮的方位
Button(root, text='退出', width=10, command=root.quit)\
             .grid(row=3, column=1, sticky=E, padx=10, pady=5) #退出直接调用根窗口的quit方法
 
mainloop()
 
#在IDLE里运行退出不了的原因是：IDLE也是用Tkinter写出来的，这里会发生冲突。若是直接双击该文件打开就可以正常退出了。



实现密码框的用星号代替实际内容，可以通过Entry的show参数来实现：

from tkinter import *
 
root = Tk()
 
Label(root, text='账号：').grid(row=0, column=0)
Label(root, text='密码：').grid(row=1, column=0)
 
v1 = StringVar()  #输入框里是字符串类型，因此用Tkinter的StringVar类型来存放
v2 = StringVar()  #需要两个变量来存放账号和密码
 
e1 = Entry(root, textvariable=v1)
e2 = Entry(root, textvariable=v2, show='*') #想要显示什么就输入什么
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)
 
def show():
    print("账号：%s" % e1.get())
    print("密码：%s" % e2.get())
 
Button(root, text='获取信息', width=10, command=show)\
             .grid(row=3, column=0, sticky=W, padx=10, pady=5)
Button(root, text='退出', width=10, command=root.quit)\
             .grid(row=3, column=1, sticky=E, padx=10, pady=5)
 
mainloop()






如果想要设计一个计算器，除了数字以外不允许其他字符出现，该怎么设计呢？

Entry组件本身就自带了验证功能，就是可以验证输入框里面内容的合法性。实现该功能，就要设置选项validate, validatecommand和invalidcommand



首先启用验证的”开关”是validate选项，该选项可以设置的值有：

'focus'：当Entry组件获得或失去焦点的时候验证（当Entry组件获得或失去焦点的时候调用validate-command指定的验证函数）

'focusin'：当Entry组件获得焦点的时候验证

'focusout'：当Entry组件失去焦点的时候验证

'key'：当输入框被编辑的时候验证

'all'：当出现上面任何一种情况的时候验证

'none'：①关闭验证功能

②默认设置该选项（即不用启用验证）

③注意：是字符串的'none'，而非None



其次是为validatecommand选项指定一个验证函数，该函数只能返回True或False表示验证的结果，一般情况下验证函数只需要知道输入框的内容即可，可以通过Entry组件的get()方法获得该字符串。



下边的例子中，在第一个输入框中输入“我爱学习”并通过Tab键将焦点转移到第二个输入框的时候，验证功能被成功触发。

from tkinter import *
 
master = Tk()
 
def test():
    if e1.get() == '我爱学习':
        print('继续努力！')
        return True
    else:
        print('你在说什么鬼话')
        e1.delete(0, END)
        return False
 
 
v = StringVar()
 
e1 = Entry(master, textvariable=v, validate='focusout', validatecommand=test)  #当焦点移出的时候调用validatecommand设置的函数test
e2 = Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)
 
mainloop()

invalidcommand选项指定的函数只有在validatecommand的返回值为False的时候才会被调用。



下边的例子中，在第一个输入框输入不是"我爱学习"以外的字符串，并通过Tab键将焦点转移到第二个输入框，validatecommand指定的验证函数被触发并返回False，接着invalidcommand被触发：

from tkinter import *
 
master = Tk()
 
def test1():
    if e1.get() == '我爱学习':
        print('继续努力！')
        return True
    else:
        print('你在说什么鬼话')
        e1.delete(0, END)
        return False
 
def test2():
    print('invalidatecommand设置的test2出场了')
 
 
v = StringVar()
 
e1 = Entry(master, textvariable=v, validate='focusout', \
           validatecommand=test1, invalidcommand=test2)
           
e2 = Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)
 
mainloop()





其实Tkinter还有隐藏功能，不过需要冷却才能实现：

Tkinter为验证函数提供一些额外的选项：

'%d'：操作代码：0表示删除操作；1表示插入操作；2表示获得、失去焦点或textvariable变量的值被修改

'%i'：当用户尝试插入或删除操作的时候，该选项表示插入或删除的位置（索引号）

如果是由于获得、失去焦点或textvariable变量的值被修改而调用验证函数，那么该值是-1

'%P'：当输入框的值允许被改变的时候，该值有效

该值为输入框的最新文本内容

'%s'：该值为调用验证函数前输入框的文本内容

'%S'：当插入或删除操作触发验证功能的时候，该值有效

该选项表示文本被插入和删除的内容

'%v'：该组件当前的validate选项的值

'%V'：调用验证函数的原因

该值是'focusin'、'focusout'、'key'或'focused'（textvariable选项指定的变量值被修改）中的一个

'%W'：该组件的名字（在Tkinter内部会注册一个名字，显示的是注册的名字，类似于句柄）



为了使用这些选项，我们可以这样写：validatecommand=(f, s1, s2, ...)---把它变成了一个元组



其中，f就是我们‘冷却后’的验证函数名，s1, s2, s3这些都是额外的选项，这些选项会作为参数依次传递给f函数。我们刚刚说了，使用额外功能前需要冷却，其实就是调用register()方法将验证函数包装起来：

from tkinter import *
 
master = Tk()
 
def test(content, reason, name):  #test不再是没有参数的方法了，参数是在validatecommand里出现的
    if content == '我爱学习':
        print('继续努力！')
        print(content, reason, name)
        return True
    else:
        print('你在说什么鬼话')
        print(content, reason, name)
        e1.delete(0, END)
        return False
 
 
v = StringVar()
 
testCMD = master.register(test)
e1 = Entry(master, textvariable=v, validate='focusout', \
           validatecommand=(testCMD, '%P', '%v', '%W'))
e2 = Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)
mainloop()




下面是设计一个简单的加法计算器：

from tkinter import *
 
master = Tk()
 
frame = Frame(master)
frame.pack(padx=10, pady=10)
 
def test(content): #有些人可能会用输入框的get方法来获取内容，再通过将validate设置为key来判断输入参数合不合法。但是validate参数设置为key后，就不再能用输入框的get方法和textvariable.get方法获取输入内容。因为validate被指定为key时，有任何输入操作都会被拦截，然后调用验证函数，验证完后只有返回True才会将内容放到textvariable关联的变量中。
    return content.isdigit()    #字符串的内置方法，是数字返回True；不是返回False
 
 
v1 = StringVar()
v2 = StringVar()
v3 = StringVar()
 
testCMD = master.register(test)
e1 = Entry(frame, width=10, textvariable=v1, validate='key', \
           validatecommand=(testCMD, '%P')).grid(row=0, column=0)  #validate的值是key，那么输入框输入的内容如果是True会保留；是False会清除。设置输入框的宽度是10个字符
 
Label(frame, text='+').grid(row=0, column=1)
 
e2 = Entry(frame, width=10, textvariable=v2, validate='key', \
           validatecommand=(testCMD, '%P')).grid(row=0, column=2)
 
Label(frame, text='=').grid(row=0, column=3)
 
e3 = Entry(frame, width=10, textvariable=v3, state='readonly').grid(row=0, column=4)
 
def calc():
    result = int(v1.get()) + int(v2.get())
    v3.set(str(result))
    
Button(frame, text='计算结果', command=calc).grid(row=1, column=2, pady=5)
 
mainloop()

/*******************************/
鱼c笔记——Python的GUI编程（五）：Tkinter组件Listbox、Scrollbar和Scale
Listbox组件，用列表框的形式显示出选项，并且支持滚动条操作。所以更适用于提供大量选项。
#Listbox
#Scrollbar
#Scale


from tkinter import *
 
master = Tk()
 
theLB = Listbox(master)
theLB.pack()
 
#theLB.insert(0, '') #向Listbox里添加选项，下标从零开始。最后可以用END
for item in ['张三', '李四', '王五']:
    theLB.insert(END, item)   #END表示最后一个。里面什么都没有时，END是0；插入一个后，END是1
 
'''
theLB.delete(0, END)
#删除Listbox里所有的选项。删除操作有两个参数：起始位置和结束位置
#如果只有一个参数，就指定删除参数对应的选项
'''
 
#添加按钮组件选中哪个按下删除哪个
theButton = Button(master, text='删除它', \
                   command=lambda x=theLB:x.delete(ACTIVE)) #ACTIVE表示当前选中的值 
theButton.pack()
 
mainloop()

Listbox组件根据selectmode选项提供了四种不同的选择模式：SINGLE（单选）、BROWSE（也是单选，但是拖动鼠标或通过方向键可以直接改变选项）、MUTIPLE（多选）和EXTENDED（也是多选，但需要同时按住Shift键或Ctrl键或拖拽鼠标实现）。默认是BROWSE。





Listbox组件默认最多只能显示10个项目，如果有11个项目怎么解决？

可以通过在Listbox内滑动鼠标滚轮使最后一个现身，但这样很容易被忽略。

有两个方法可以避免：

①修改height选项。height选项是用来设置Listbox显示的行数（不是像素），其默认值是10

但是如果要显示项目过多，比如说1000个，修改height就不太合适了，因为总不能显示1000行

②可以为Listbox组件添加滚动条。





Scrollbar滚动条组件：

滚动条组件虽然是一个独立的组件，但几乎都是与其他组件一起配合使用。



为了在某个组件上安装垂直滚动条，你需要做两件事：

1.设置该组件的yscrollcommand选项为Scrollbar组件的set()方法

2.设置Scrollbar组件的command选项为该组件的yview()方法



下面是一个在Listbox里添加滚动条的例子：

from tkinter import *
 
root = Tk()
 
sb = Scrollbar(root)
sb.pack(side=RIGHT, fill=Y)  #把滚动条加到右边去，填充整个y轴
 
lb = Listbox(root, yscrollcommand=sb.set)
#在Listbox里滑动鼠标滚轮时调用set方法，同时修改滚动条的位置
 
for i in range(1000):
    lb.insert(END, i)
lb.pack(side=LEFT, fill=BOTH)
 
#要与滚动条互通互连，要设置滚动条的command选项
sb.config(command=lb.yview)  #config方法设置某个选项的值
#yview方法是Listbox里的默认方法，方法已经设置好怎么显示垂直滚动对应的内容变化
#拖动垂直滚动条时调用yview
 
mainloop()





既然说到了滚动条，就继续来说说和滚动条组件很相似的一个组件Scale组件。

Scale组件主要通过滑块来表示某个范围内的一个数字。可以设置选项范围和分辨率（分辨率指的是步长，也就是精度）

from tkinter import *
 
#当我们希望用户输入某个范围内的数字的时候，可能会使用Entry组件，但是Entry组件并不能限制一个范围
root = Tk()
 
s1 = Scale(root, from_=0, to=42)  #有两个参数from和to，但是from参数和Python的关键字冲突了，所以加个下横线
s1.pack()
 
s2 = Scale(root, from_=0, to=200, orient=HORIZONTAL)  #默认Scale是垂直的，可以修改orient参数成水平的
s2.pack()
 
#获取滑块当前位置使用的是get方法
def show():
    print(s1.get(), s2.get())
 
Button(root, text='获取位置', command=show).pack()
 
mainloop()

可以通过设置选项tickinterval和resolution改变步长和精度：

from tkinter import *
 
root = Tk()
 
#tickinterval=5每5个步长显示刻度
#resolution设置每次移动多少个长度，等于5的话，每次改变只能改变5
#设置length长度，不然都堆在一起了
s1 = Scale(root, from_=0, to=42, tickinterval=5, resolution=5, length=200).pack()
s2 = Scale(root, from_=0, to=200, tickinterval=10, orient=HORIZONTAL, length=600).pack()
 
mainloop()

/***************************/
鱼c笔记——Python的GUI编程（八）：Tkinter的Canvas组件1
#Canvas


Canvas组件是一个通用的组件，通常用于显示和编辑图形，我们可以用它来绘制直线三角形多边形甚至是绘制其他的组件，所以说Canvas组件可以让我们随心所欲的绘制界面。



在Canvas上绘制对象，我们可以使用create方法

from tkinter import *
 
root = Tk()
 
w =Canvas(root, width=200, height=100)  #width和height单位是像素
w.pack()
#到这里还是看不见Canvas的，不过可以通过设置Canvas的background属性来改变背景颜色
 
#create后面加上下横线再加上我们要绘制对象的名字
w.create_line(0, 50, 200, 50, fill='yellow')  #前两个参数描述的是直线的起始位置是水平方向的第0个像素和竖直方向的第50像素。fill设置填充颜色
w.create_line(100, 0, 100, 100, fill='red', dash=(4, 4))  #dash是设置虚线
w.create_rectangle(50, 25, 150, 75, fill='blue')  #左上角右下角的坐标
#这三个画布对象没有意外的话会一直保留着，直到你去修改它们，它们就可能会被覆盖。
#例如说这条黄线本来是从左至右贯穿整个Canvas的，但是被矩形覆盖了，中间被覆盖的位置就看不到了
#还有一些方法可以对这些画布对象进行修改，如Canvas实例对象的coords() itemconfig() move()方法,删除的话可以用delete()方法。下例将进行演示
 
mainloop()




下面将演示如何修改画布对象。使用的方法在上例的注释有提及

from tkinter import *
 
root = Tk()
 
w =Canvas(root, width=200, height=100)
w.pack()
 
line1 = w.create_line(0, 50, 200, 50, fill='yellow')
line2 = w.create_line(100, 0, 100, 100, fill='red', dash=(4, 4))
rect1 = w.create_rectangle(50, 25, 150, 75, fill='blue')
 
w.coords(line1, 0 ,25, 200, 25)  #用该方法把对象移动到一个新的位置
w.itemconfig(rect1, fill='red')  #主要是设置对象的选项
w.delete(line2)  #直接将对象的名字放进去就可以实现删除
 
Button(root, text='删除全部对象', command=(lambda x=ALL:w.delete(x))).pack()
#ALL是一个tag，表示所有的对象
 
mainloop()

还可以在Canvas上显示文本：

from tkinter import *
 
root = Tk()
 
w =Canvas(root, width=200, height=100)
w.pack()
 
w.create_line(0, 0, 200, 100, fill='green', width=3) #线的宽度为3个像素
w.create_line(200, 0, 0, 100, fill='green', width=3)
w.create_rectangle(40, 20, 160, 75, fill='green')
w.create_rectangle(65, 35, 135, 65, fill='yellow')
 
w.create_text(100, 50, text='Study')  #可以修改ancoror选项使文本起始位置改变
 
mainloop()



在Canvas上画圆形或椭圆形

from tkinter import *
 
root = Tk()
 
w =Canvas(root, width=200, height=100)
w.pack()
 
w.create_rectangle(40, 20, 160, 80, dash=(4, 4))
w.create_oval(40, 20, 160, 80, fill='pink')  #前面四个参数表示限定矩形所在的位置
#圆形就是限定矩形为正方形
#如w.create_oval(70, 20, 130, 80, fill='pink')
 
w.create_text(100, 50, text='Study')
 
mainloop()




Canvas上画多边形可以使用create_polygon方法。下例是画一个五角星，首先要确定五个角的坐标：

from tkinter import *
import math as m
 
root = Tk()
 
w =Canvas(root, width=200, height=100)
w.pack()
 
center_x = 100  #五角星中心点的坐标和半径
center_y = 50
r = 50
 
points = [
    #左上点
    center_x - int(r * m.sin(2 * m.pi / 5)),
    center_y - int(r * m.cos(2 * m.pi / 5)),
    #右上点
    center_x + int(r * m.sin(2 * m.pi / 5)),
    center_y - int(r * m.cos(2 * m.pi / 5)),
    #左下角
    center_x - int(r * m.sin(m.pi / 5)),
    center_y + int(r * m.cos(m.pi / 5)),
    #顶点
    center_x,
    center_y - r,
    #右下点
    center_x + int(r * m.sin(m.pi / 5)),
    center_y + int(r * m.cos(m.pi / 5)),
    ]
 
w.create_polygon(points, outline='green', fill='yellow') #方法把传入的两个点间连一条线，反复调用该方法看可以画出一个多边形
 
mainloop()

/***************************/
鱼c笔记——Python的GUI编程（十二）：Tkinter的组件Message

#Message



Tkinter的Message（消息）组件：

Message组件实际上是Label组件（只能显示单行）的变体，用于显示多行文本消息。Message组件能够自动换行，并调整文本的尺寸使其适应给定的尺寸。



下面的例子是演示自动换行的功能：

from tkinter import *
 
root = Tk()
 
w1 = Message(root, text='这是一条短消息', width=100)
w1.pack()
 
w2 = Message(root, text='这是一条超级超级超级超级无敌巨无霸长的消息', width=100)  #文本中也可以加上\n进行强制换行
w2.pack()
 
mainloop()
何时使用Message组件？

Message组件用于显示简单的文本消息，通常你可以使用Label来代替。如果你希望使用多种字体来显示文本，那么应该使用Text组件。



用法：

创建一个Message组件，所有你要做的事情就是指定要显示的文本内容。在必要的时候，该组件会自动换行，



参数

Message(master=None, **options)(class)

master----父组件

**options----组件选项，下方各表格详细列举了各个选项的具体含义和用法：

anchor--控制文本消息的显示位置

--N, NE, E, SE, S, SW, W, NW或CENTER来定位（EWSN代表东西南北）

--默认值是CENTER

aspect--设置高宽比，即宽度/高度的百分比的值

--默认值是150（宽度比高度大50%）

--注意：如果设置了width选项的值，该选项将被忽略

background--设置背景颜色

--默认值由系统指定

bg--跟background一样

borderwidth--指定边框高度

--默认值由系统指定，通常是1或2像素

bd--跟borderwidth一样

cursor--指定当鼠标在Message是飘过的时候的鼠标样式

--默认值由系统指定

font--指定Message中文本的字体

--只能指定一种字体

--默认值由系统指定

foreground--设置Message的文本的颜色

--默认值由系统指定

fg--和foreground一样

highlightbackground--指定当Message没有获得焦点的时候高亮边框的颜色

--默认值由系统指定，通常是标准背景颜色

highlightcolor--指定当Message获得焦点的时候高亮边框的颜色

--默认值由系统指定

highlightthickness--指定高亮边框的宽度

--默认值是0（不带高亮边框）

justify--定义如何对齐多行文本

--使用LEFT，RIGHT或CENTER

--注意，文本的位置取决于anchor选项

--默认值是CENTER

padx--指定水平方向上的额外间距（内容和边框间）

--单位是像素

pady--指定垂直方向上的额外间距（内容和边框间）

--单位是像素

relief--指定边框样式

--默认值是FLAT

--另外你还可以设置SUNKEN，RAISED，GROOVE或RIDGE

takefocus--如果是True，该组件接受输入焦点

--默认值是False

text--指定Label显示的文本

--为了达到指定的高宽比（aspect选项指定），文本内容将自动进行换行

textvariable--Message显示Tkinter的变量（通常是一个StringVar变量）的内容

--如果变量被修改，Message的文本会自动更新

width--设置Message的宽度

--单位是文本单位

--如果忽略该选项，将根据aspect设置的高宽比来设置合适的宽度
/***************************/
鱼c笔记——Python的GUI编程（十五）：Tkinter的组件Toplevel及Tk和Toplevel的方法
#Toplevel
#Tk



Toplevel（顶级窗口）组件类似于Frame组件，但Toplevel组件是一个独立的顶级窗口，这种窗口通常拥有标题栏、边框等部件，和Tk()创建出来的根窗口是一样的，共享着一样的方法。



何时使用Toplevel组件？

Toplevel组件通常用在显示额外的窗口、对话框或者其他弹出窗口上。



下面的例子，我们在root窗口添加一个按钮用于创建一个顶级窗口，点一下来一个。

from tkinter import *
 
root = Tk()
 
def create():
    top = Toplevel()
    top.title('Python')
 
    msg = Message(top, text='I love study')
    msg.pack()
 
Button(root, text='创建顶级窗口', command=create).pack()
 
mainloop()






Tk（根窗口）和Toplevel（顶级窗口）的方法：

下边这一系列方法用于与窗口管理器进行交互。他们可以被Tk（根窗口）调用，同时也适用于Toplevel（顶级窗口）。

注意：并非所有操作系统均完全支持下方所有方法的实现。



aspect(minNumber=None, minDenom=None, maxNumber=None, maxDenom=None,)

--控制该窗口的宽高比(width:height)

--宽高比限制在：minNumber/minDenom~maxNumber/maxDenom

--如果忽略参数，则返回一个4元组表示当前的限制（如果有的话）



attribute(*args)

--设置和获取窗口属性

--如果你只给出选项名，将返回当前窗口该选项的值

--注意：以下选项不支持关键字参数，你需要在选项前加横岗（-）并用字符串的方式表示，用逗号（,）隔开选项和值。

--例如你希望设置窗口的透明度为50%，你应该使用attribute("-alpha", 0.5)代替attribute(alpha=0.5)

--下方列举了args可以使用各个选项的具体含义和用法：

alpha：（Windows，Mac）控制窗口的透明度

1.0表示不透明，0.0表示完全透明

该选项并不支持所有的系统，对于不支持的系统，Tkinter绘制一个不透明（1.0）的窗口

disabled：（Windows）禁用整个窗口（这时候你只能从任务管理器中关闭它）

fullscreen：（Windows，Mac）如果设置为True，则全屏显示窗口

modified：（Mac）如果设置为True，该窗口被标记为改动过

titlepath：（Mac）设置窗口代理图标的路径

toolwindow：（Windows）如果设置为True，该窗口采用工具窗口的样式

topmost：（Windows，Mac）如果设置为True，该窗口将永远置顶



client(name=None)

--设置和获取WM_CLIENT_MACHINE属性

--如果要删除WM_CLIENT_MACHINE属性，赋值为空字符串即可

--该属性仅支持X窗口系统的窗口管理器，其他系统均忽略



colormapwindows(*wlist)

--设置和获取WM_COLORMAP_WINDOWS属性

--该属性仅支持X窗口系统的窗口管理器，其他系统均忽略



command(value=None)

--设置和获取WM_COMMAND属性

--该属性仅支持X窗口系统的窗口管理器，其他系统均忽略



deiconify()

--显示窗口

--默认情况下新创建的窗口都会显示在屏幕上，但是用iconify()或withdraw()方法可以在屏幕上移除窗口



focusmodel(model=None)

--设置和获取焦点模式



frame()

--返回一个字符串表示当前系统特征

--对于类Unix系统，返回值是X窗口标识符

--对于Windows系统，返回值是HWND强制转换为长整形的结果



geometry(geometry=None)

--设置和获取窗口的尺寸

--geometry的参数格式为："%dx%d%+d%+d"%(width, height, xoffset, yoffset)



(wm_)grid(baseWidth=None, baseHeight=None, widthInc=None, heightInc=None)

--通知窗口管理器该窗口将以网格的形式重新调整尺寸

--baseWidth和baseHeight指定Tk_GeometryRequest要求的网格单元数

--widthInc和heightInc指定单元的高度和宽度



(wm_)group(window=None)

--将窗口添加到窗口群中

--window参数指定控制窗口群的主窗口

--如果忽略该选项，将返回当前窗口群的主窗口



(wm_)iconbitmap(bitmap=None, default=None)

--设置和获取窗口的图标

--例如root.iconbitmap(bitmap="python.ico")

--default参数可以用于指定由该窗口创建的子窗口的默认图标



(wm_)iconify()

--将窗口图标化（最小化）

--需要重新显示窗口，用deiconify()方法

--该方法会使得state()返回"iconic"



(wm_)iconmask(bitmap=None)

--设置和获取位图编码



(wm_)iconname(newName=None)

--设置和获取当前窗口图标化（最小化）时的图标名字



(wm_)iconposition(x=None, y=None)

--设置和获取当前窗口图标化（最小化）时的图标位置



(wm_)iconwindow(pathName=None)

--设置和获取当前窗口图标化（最小化）时的组件窗口

--该方法会使得state()返回“icon”



(wm_)maxsize(width=None, height=None)

--设置和获取该窗口的最大尺寸



(wm_)minsize(width=None, height=None)

--设置和获取该窗口的最小尺寸



(wm_)overrideredirect(boolean=None)

--如果参数为True，该窗口忽略所有的小部件（也就是说该窗口将没有传统的标题栏、边框等部件）



(wm_)positionfrom(who=None)

--指定窗口位置由“谁决定

--如果who参数是“user”，窗口位置由用户决定

--如果who参数是“program”，窗口位置由系统决定



(wm_)protocol(name=None, func=None)

--将回调函数func与相应的规则name绑定

--name参数可以是“WM_DELETE_WINDOW”：窗口被关闭的时候

--name参数可以是“WM_SAVE_YOURSELF”：窗口被保存的时候

--name参数可以是“WM_TAKE_FOCUS”：窗口获得焦点的时候



(wm_)resizable(width=None, height=None)

--指定是否可以改变该窗口的尺寸

--width为True说明允许调整窗口的水平尺寸

--height为True说明允许调整窗口的垂直尺寸



(wm_)sizefrom(who=None)

--指定窗口尺寸由“谁决定

--如果who参数是“user”，窗口尺寸由用户决定

--如果who参数是“program”，窗口尺寸由系统决定



(wm_)state(newstate=None)

--设置和获得当前窗口的状态

--newstate的只可以是'normal', 'iconoc'(见iconify), 'withdraw'(见withdraw), 'icon'(见iconwindow)和'zoomed'(放大，Windows特有)



(wm_)title(string=None)

--设置窗口的标题



(wm_)transient(master=None)

--指定为master的临时窗口



(wm_)withdraw()

--将窗口从屏幕上移除（并没有销毁）

--需要重新显示窗口，使用deiconify()方法

--该方法会使得state()返回"withdraw"



wm_aspect(minNumber=None, minDenom=None, maxNumber=None, manDenom=None)

--见上方aspect()



wm_attributes(*args)

--见上方attributes()



wm_client(name=None)

--见上方client()



wm_colormapwindows(*wlist)

--见上方colormapwindows()



wm_command(value=None)

--见上方command()



wm_deiconify()

--见上方deiconify()



wm_focusmodel(model=None)

--见上方focusmodel()



wm_frame()

--见上方frame()



wm_geometry(geometry=None)

--见上方geometry()

/**************************/
鱼c笔记——Python的GUI编程（十三）：Tkinter的组件Spinbox

#Spinbox



组件Spinbox（Tk8.4新增）

Spinbox组件是Entry组件（能让用户随意的输入数据）的变体，用于从一些固定的值（可以是连续的，也可以是一些字符串的组合）中选取一个。



何时使用Spinbox组件？

Spinbox组件通常用于在限定数字中选取的情况下替代普通的Entry组件。

注意：Spinbox仅支持Python3.2和Tk8.4以上的版本



用法：

Spinbox组件跟Entry组件的用法非常相似，主要区别是使用Spinbox组件，你可以通过范围或者元组指定允许用户输入的内容。

from tkinter import *
 
root = Tk()
 
w = Spinbox(root, from_=0, to=10)  #from与Python的关键字冲突，故加上个下划线。步进可以设置
w.pack()
 
mainloop()


你还可以通过元组指定允许输入的值

from tkinter import *
 
root = Tk()
 
w = Spinbox(root, values = (1, '2', '3', 'hi'))  #from与Python的关键字冲突，故加上个下划线
w.pack()
 
mainloop()

参数

Spinbox(master=None, **options)(class)

master--父组件

**options--组件选项，下面是各个选项的具体含义和用法：



activebackground：设置当Spinbox处于ACTIVE状态下的背景颜色

background：设置背景颜色

默认值由系统指定。

bg：跟background一样

borderwidth：设置边框宽度

默认值是1或2像素

buttonbackground：设置调节箭头的背景颜色

buttoncursor：指定当鼠标在调节箭头上方的鼠标样式

buttondownrelief：指定向下调节箭头的样式

默认值是RAISED

还可以设置为FLAT，SUNKEN，GROOVE和RIDGE

buttonup：指定向上调节箭头的样式

默认值是RAISED

还可以设置为FLAT，SUNKEN，GROOVE和RIDGE

command：指定一个函数，当用户点击调节箭头的时候将自动调用该函数

注意：当用户直接在输入框中输入数据时并不会触发该函数

cursor：指定当鼠标在Spinbox上飘过的时候的鼠标样式

默认值由系统指定

disabledbackground：设置当Spinbox处于DISABLED状态下的背景颜色

disabledforeground：设置当Spinbox处于DISABLED状态下的前景颜色

exportselection：指定选中的文本是否可以被复制到剪贴板

默认值是True

可以修改为False表示不允许复制文本

font：指定Spinbox中文本的字体

默认值由系统指定

foreground：设置前景（文本）颜色

默认值由系统指定

fg：跟foreground一样

format：使用该选项设置选择数值的样式（from_和to指定范围，用户自行输入的不算）

例如使用format='%10.4f'表示显示的数值占10位，小数点后保留4位

from_：该选项和to选项共同指定一个范围内的数值

increment选项设置每次点击调节箭头递增递减的精度

highlightbackground：指定当Spinbox没有获得焦点的时候高亮边框的颜色

默认值由系统指定，通常是标准背景颜色



highlightcolor：指定当Spinbox获得焦点的时候高亮边框的颜色

默认值由系统指定

highlightthickness：指定高亮边框的宽度

increment：该选项指定当用户每次点击调节箭头的时候递增递减的精度

例如from_=1, to=10, increment=0.5，那么每次用户点击调节箭头的时候，输入框中的数字递增递减0.5

insertbackground：指定输入光标的颜色

insertborderwidth：指定输入光标的边框高度

如果被设置为非0值，光标样式会被设置为RAISED

提示：将insertborderwidth设置的大一点才能看到效果

insertofftime：该选项控制光标的闪烁频率（灭）

单位是毫秒

insertontime：该选项控制光标的闪烁频率（亮）

单位是毫秒

insertwidth：指定光标的宽度

默认值是1或2像素

invalidcommand：指定当输入框的内容“非法”时调用的函数

也就是指定当validateCommand选项指定的函数返回False时的函数

详见Entry组件

invcmd：跟invalidcommand一样

justify：定义如何对齐多行文本

使用LEFT，RIGHT或CENTER

默认值是CENTER

readonlybackground：设置当Spinbox处于“readonly”状态下的背景颜色

relief：指定边框样式

默认值是FLAT

另外你还可以设置SUNKEN，RAISED，GROOVE或RIDGE

repeatdelay：该选项指定鼠标左键点击滚动条凹槽的响应时间

默认值是400（毫秒）

repeatinterval：该选项指定鼠标左键紧按滚动条凹槽的响应间隔

默认值是100（毫秒）

selectbackground：指定输入框的文本被选中时的背景颜色

默认值由系统指定

state：Spinbox组件可以设置的状态：NORMAL，DISABLED或“readonly”（注意，这个是字符串。它跟DISABLED相似，但他支持选中和拷贝，只是不能修改，而DISABLED是完全禁止）

默认值是NORMAL

注意，如果此选项设置为DISABLED或”readonly”，那么调用insert()和delete()方法都会被忽略。

takefocus：指定使用Tab键可以将焦点移动到输入框中

默认是开启的，可以将该选项设置为False避免焦点在此输入框中

textvariable：指定一个与输入框内容相关联的Tkinter变量（通常是StringVar）

当输入框的内容发生改变时，该变量的值也会相应发生改变

to：该选项和from_选项共同指定一个范围的数值

increment选项设置每次点击调节箭头递增递减的精度

validate：该选项设置是否启用内容验证

validatecommand：该选项指定一个验证函数，用于验证输入框内容是否合法

验证函数需要返回True或False表示验证结果

注意，该选项只有当validate的值非'none'时才有效

vcmd：和validatecommand一样



values：提供两个方法限定用户输入的内容，一种是通过from_和to选项设置范围，另一种则是将可选值以元组的形式赋给values选项

例如values=("ds", "sad", "aesf")则允许用户在这四个字符串中选择

width：设置输入框的宽度，以字符为单位

默认值是20

对于变宽字体来说，组件的实际宽度等于字体的平均宽度乘以width选项的值

wrap：默认情况下（False），当输入框中的值是第一个（最后一个）的时候，再点击向上（向下）调节箭头，内容不会改变。

当该选项的值设置为True，则当输入框中的值是第一个（最后一个）的时候，再点击向上（向下）调节箭头，内容将回到最后一个（第一个）。

提示：其实就是开启循环的意思

xscrollcommand：与scrollbar（滚动条）组件相关联

如果你觉得用户输入的内容会超过该组件的输入框宽度，那么可以考虑设置该选项


/***************************/

鱼c笔记——Python的GUI编程（十四）：Tkinter的组件PanedWindow
#PanedWindow



PanedWindow（窗格）组件（Tk8.4新增是一个空间管理组件。跟Frame组件类似，都是为组件提供一个框架，不过PanedWindow允许让用户调整应用程序的空间划分。



何时使用PanedWindow组件？

当你需要提供一个可供用户调整的多空间框架的时候，可以使用PanedWindow组件。PanedWindow组件会为每一个子组件生成一个独立的窗格，用户可以自由调整窗格的大小。



用法：

from tkinter import *
 
m = PanedWindow(orient=VERTICAL)
m.pack(fill=BOTH, expand=1)
 
top = Label(m, text='top pane')
m.add(top)
 
bottom = Label(m, text='bottom pane')
m.add(bottom)
#拖拽鼠标的左键可以改变布局
#中间有条隐藏的线，是二窗格
 
mainloop()

#创建一个三窗格
from tkinter import *
 
m1 = PanedWindow()  #默认是左右分布的
m1.pack(fill=BOTH, expand=1)
 
left = Label(m1, text='left pane')
m1.add(left)
 
m2 = PanedWindow(orient=VERTICAL)
m1.add(m2)
 
top = Label(m2, text='top pane')
m2.add(top)
 
bottom = Label(m2, text='bottom pane')
m2.add(bottom)
 
mainloop()

#显示手柄和分割线
from tkinter import *
 
m1 = PanedWindow(showhandle=True, sashrelief=SUNKEN)  #默认是左右分布的
m1.pack(fill=BOTH, expand=1)
 
left = Label(m1, text='left pane')
m1.add(left)
 
m2 = PanedWindow(orient=VERTICAL, showhandle=True, sashrelief=SUNKEN)
m1.add(m2)
 
top = Label(m2, text='top pane')
m2.add(top)
 
bottom = Label(m2, text='bottom pane')
m2.add(bottom)
 
mainloop()
#分割线上的类似正方形的东西就是handle







参数

PanedWindow(master=None, **options)(class)

master--父组件

**options--组件选项，下方详细列举了各个选项的具体含义和用法



background：设置背景颜色

bg：跟background一样

borderwidth：设置边框宽度

bd：跟borderwidth一样

cursor：指定当鼠标在PanedWindow上飘过的时候的鼠标样式

默认值由系统指定

handlepad：调节“手柄”的位置

例如orient=VERTICAL，则handlepad选项表示“分割线”上的手柄与左端的距离

默认值是8像素

handlesize：设置“手柄”的尺寸（由于“手柄”必须是一个正方形，所以是设置正方形的边长）

默认值是8像素

height：设置PanedWindow的高度

如果忽略该选项，则高度由子组件的尺寸决定

opaqueresize：该选项定义了用户调整窗格尺寸的操作

如果该选项的值为True（默认），窗格的尺寸随用户鼠标的拖拽而改变

如果该选项的值为False，窗格的尺寸在用户释放鼠标的时候才更新到新的位置

orient：指定窗格的分布方式

可以是HORIZONTAL（横向分布）和VERTICAL（纵向分布）

relief：指定边框样式

默认值是FLAT

另外你还可以设置SUNKEN，RAISED，GROOVED或RIDGE

sashpad：设置每一条分割线到窗格间的间距

sashrelief：设置分割线的样式

默认值是FLAT

另外你还可以设置SUNKEN，RAISED，GROOVED或RIDGE

sashwidth：设置分割线的宽度

showhandle：设置是否显示调节窗格的手柄

默认值为False

width：设置PanedWindow的宽度

如果忽略该选项，则高度由子组件的尺寸决定



方法：

add(child, **options)

--添加一个新的子组件到窗格中

--下方表格列举了各个options选项的具体含义

after：添加新的子组件到指定子组件后边

before：添加新的子组件到指定子组件qianb

height：指定子组件的高度

minsize：该选项控制窗格不得低于的值

如果orient=HORIZONTAL，表示窗格的宽度不得低于该选项的值

如果orient=VERTICAL，表示窗格的高度不得低于该选项的值

padx：指定子组件的水平间距

pady：指定子组件的垂直间距

sticky：当窗格的尺寸大于子组件时，该选项指定子组件位于窗格的位置

可选的值有：E、S、W、N（东南西北）以及他们的组合值

width：指定子组件的宽度



forget(child)

--删除一个子组件



identify(x, y)

--给定一个坐标(x, y)，返回该坐标所在的元素名称

--如果该坐标位于子组件上，返回空字符串

--如果该坐标位于分割线上，返回一个二元组(n, 'sash')，n为0表示第一个分割线

--如果该坐标位于手柄上，返回一个二元组(n, 'handle')，n为0表示第一个手柄



panecget(child, option)

--获得子组件指定选项的值



panecget(child, option)

--获得子组件指定选项的值



paneconfig(child, **option)

--设置子组件的各种选项

--下面列举了各个options选项具体含义

after：添加新的子组件到指定子组件后边

before：添加新的子组件到指定子组件前边

height：指定子组件的高度

/***************************/

鱼c笔记——Python的GUI编程（十一）：Tkinter事件绑定
#事件绑定



一个Tkinter应用程序大部分时间是花在事件循环当中的，也就是通过mainloop()进入的事件循环。

事件可以有各种来源：用户触发的鼠标和键盘操作和窗口管理器触发的重绘事件（在多数情况下是由用户简介引起的）

Tkinter给我们提供了一个强大的机制去管理这些事件，去定义这些事件的操作。对每一个组件来说，可以通过bind()的方法来将自己定义的函数或方法绑定到具体的事件上。

widget.bind(event, handler)
 

当被触发的事件满足该组件绑定的事件的时候，Tkinter就会带着事件对象（Event、事件本身的描述）去调用自定义的handler()方法。

 

 

捕获鼠标点击的位置的演示：


 
from tkinter import *

 
root =Tk()

 
#当触发<Button-1>，Tkinter会带着事件本身去调用callback，会把它传入到callback中，因此要个形参来接收对应的事件描述

def callback(event):

print("点击位置：", event.x, event.y) #这个x和y表示的是相对于应用程序左上角的x和y。root的x和y相对的是屏幕

 
frame = Frame(root, width=200, height=200)

frame.bind("<Button-1>", callback) # -左边是事件本身，右边是事件详细描述。Button表示的是鼠标的点击事件，1表示的是左键，2代表滚轮，3表示右键，4、5对于Linux系统才有用，表示滚轮向上滚和向下滚。对于Windows和Mac系统来说则是通过mousewhell来表示用户是向上滚还是向下滚了滚轮。

frame.pack()

 
mainloop()

 

关于键盘的演示：


 
from tkinter import *

 
root =Tk()

 
def callback(event):

print(event.char) #获取当前键盘按下的字符

 
frame = Frame(root, width=200, height=200)

frame.bind("<Key>", callback) #组件想要响应键盘事件，组件必须获得焦点，组件才会响应键盘来的消息。因为一个窗口可以有很多组件，键盘一次敲击不知道给哪个组件。

frame.focus_set() #通过focus_set方法获得焦点。也可以设置Frame的takefocus选项为True，然后使用Tab将焦点转移上来

frame.pack()

 
mainloop()

 

利用<Motion>事件获取鼠标实时位置的方式


 
from tkinter import *

 
root =Tk()

 
def callback(event):

print("当前位置：", event.x, event.y)

 
frame = Frame(root, width=200, height=200)

frame.bind("<Motion>", callback) #Motion事件表示当鼠标进入组件时，就会响应这个事件

frame.focus_set()

frame.pack()

 
mainloop()

 

 

下方主要内容：

1.事件序列

2.type

3.modifier

4.Event对象

5.Key names

 

事件序列：

Tkinter使用一种称为事件序列的机制来允许用户定义事件，用户需要使用bind()方法将具体的事件序列与自定义的方法相绑定。事件序列是以字符串的形式表示的，可以表示一个或多个相关联的事件（若果是多个事件，那么对应的方法只有在满足所有事件的前提下才会被调用）

 

事件序列使用以下语法描述：

<modifier-type-detail>
事件序列是包含在尖括号（<...>）中的

type部分的内容是必须的，它通常用于描述普通的事件类型，例如鼠标点击或键盘按键点击

modifier部分的内容是可选的，它通常用于描述组合键，例如Ctrl + c（<Control-Key-C>），Shift + 鼠标左键点击（<Shift-Button-1>）

detail部分的内容是可选的，它通常用于描述具体的按键，例如Button-1表示的是鼠标左键

 

如：

事件序列<Button-1>：用户点击鼠标左键

事件序列<KeyPress-H>：用户点击H按键

事件序列<Control-Shift-KeyPress-H>：用户同时点击Ctrl + Shift +H

 

type

type: Active：当组件的状态从“未激活”变为“激活”的时候触发该事件

Button：当用户点击鼠标按键的时候触发该事件

detail部分指定是具体用哪个键：<Button-1>鼠标左键，<Button-2>鼠标中键（滚轮点击），<Button-3>鼠标右键，<Button-4>滚轮上滚（Linux），<Button-5>滚轮下滚（Linux）

ButtonRelease：当用户释放鼠标按键的时候触发该事件

在大多数情况下，比Button要更好使用，因为如果当用户不小心按下鼠标键，用户可以将鼠标移出组件再释放鼠标，从而避免不小心触发事件

Configure：当组件的尺寸改变的时候触发该事件（窗口管理器触发的重绘事件，当你调整组件的尺寸或者移动应用程序，组件会和窗口一样被重绘）

Deactivate：当组件的状态从“激活”变为“未激活”的时候触发该事件

Destroy当组件被销毁时触发该事件

Enter：当鼠标指针进入组件的时候触发该事件

注意：不是用户按下回车键（回车键是Return<Key-Return>）

Expose：当窗口或组件的某部分不再被覆盖的时候触发该事件

FocusIn：当组件获得焦点的时候触发该事件

用户可以用Tab键将焦点转移到该组件上（需要该组件的takefocus选项为True）

你也可以调用focus_set()方法使该组件获得焦点

FocusOut：当组件失去焦点的时候触发该事件

KeyPress：当用户按下键盘按键的时候触发该事件

detail可以指定具体的按键，例如<KeyPress-H>表示当大写字母H被按下的时候触发该事件

KeyPress可以缩写为Key

KeyRelease：当用户释放键盘按键的时候触发该事件

Leave：当鼠标指针离开组件的时候触发该事件

Map：当组件被映射的时候触发该事件

意思是在应用程序中显示该组件的时候，例如调用get()方法

Motion：当鼠标在组件内移动的时候触发该事件

MouseWheel当鼠标滚轮滚动的时候触发该事件

目前该事件仅支持Windows和Mac系统

Unmap：当组件被取消映射的时候触发该事件

意思是在应用程序中不再显示该组件的时候，例如调用grid_remove()方法

Visibility：当应用程序至少有一部分在屏幕中是可见的时候触发该事件

 

 

modifier

在事件序列中，modifier部分的内容可以是以下这些：

Alt：当按下Alt按键的时候

Any：表示任何类型的按键被按下的时候

例如<Any-keyPress>表示当用户按下任何按键时触发事件

Control：当按下Ctrl按键的时候

Double：当后续两个事件被连续触发的时候

例如<Double-Button-1>表示当用户双击鼠标左键时触发事件

Lock：当打开大写字母锁定键（CapsLock）的时候

Shift：当按下Shift按键的时候

Triple：跟Double类似，当后续三个事件被连续触发的时候

 

Event对象：

当Tkinter去回调你定义的函数的时候，就会带着Event对象（作为参数）去调用，Event对象以下这些属性你可以使用：

widget：产生该事件的组件

x, y：当前的鼠标的位置坐标（相对于窗口左上角，单位为像素）

x_root, y_root：当前的鼠标的位置坐标（相对于屏幕左上角，单位为像素）

char：按键对应的字符（键盘事件专属，不会显示Control，Shift等键）

keysym：按键名，见下方Key names（键盘事件专属）

keycode：按键码，见下方Key names（键盘事件专属）

num：按钮数字（鼠标事件专属）

width, height：组件的新尺寸（Configure事件专属）

type：该事件类型

 

Key names

当事件为<Key>，<KeyPress>，<KeyRelease>的时候，detail可以通过设定具体的按键名(keysym)来筛选。例如<Key-H>表示按下键盘上的大写字母H时候触发事件，<Key-Tab>表示按下键盘上的Tab按键的时候触发事件。

下边列举了键盘所有特殊按键的keysym和keycode（按键码是对应美国标准101键盘的“Lantin-1”字符集，键盘标准不同，对应的按键码不同，但按键名是一样的）


 
按键名（keysym） 按键码（keycode） 代表的按键

Alt_L 64 左边的Alt按键

Alt_R 113 右边的Alt按键

BackSpace 22 BackSpace（退格）按键

Cancel 110 break按键

Caps_Lock 66 CapsLock（大写字母锁定）按键

Control_L 37 左边的Control

Control_R 109 右边的Control

Delete 107 Delete按键

Down 104 ↓按键

End 103 End按键

Escape 9 Esc按键

Execute 111 SysReq按键

F1 67 F1按键

F2 68 F2按键

F3 69 F3按键

F4 70 F4按键

F5 71 F5按键

F6 72 F6按键

F7 73 F7按键

F8 74 F8按键

F9 75 F9按键

F10 76 F10按键

F11 77 F11按键

F12 96 F12按键

Home 97 Home按键

Insert 106 Insert按键

Left 100 ←按键

Linefeed 54 Linefeed（Ctrl + J）

KP_0 72 小键盘数字0

KP_1 73 小键盘数字1

KP_2 74 小键盘数字2

KP_3 75 小键盘数字3

KP_4 76 小键盘数字4

KP_5 77 小键盘数字5

KP_6 78 小键盘数字6

KP_7 79 小键盘数字7

KP_8 80 小键盘数字8

KP_9 81 小键盘数字9

KP_Add 86 小键盘的+按键

KP_Begin 84 小键盘的中间按键（5）

KP_Decimal 91 小键盘的点按键（.）

KP_Delete 91 小键盘的删除键

KP_Divide 112 小键盘的/按键

KP_Down 88 小键盘的↓按键

KP_End 87 小键盘的End按键

KP_Enter 108 小键盘的Enter按键

KP_Home 79 小键盘的Home按键

KP_Insert 90 小键盘的Insert按键

KP_Left 83 小键盘的←按键

KP_Mutiply 63 小键盘的*按键

KP_Next 89 小键盘的PageDown按键

KP_Prior 81 小键盘的PageUp按键

KP_Right 85 小键盘的→按键

KP_Subtract 82 小键盘的-按键

KP_Up 80 小键盘的↑按键

Next 105 PageDown按键

Num_Lock 77 NumLock（数字锁定）按键

Pause 110 Pause（暂停）按键

Print 111 PrintScrn（打印屏幕）按键

Prior 99 PageUp按键

Return 36 Enter（回车）按键

Right 102 →按键

Scroll_Lock 78 ScrollLock按键

Shift_L 50 左边的Shift按键

Shift_R 62 右边的Shift按键

Tab 23 Tab（制表）按键

Up 98 ↑按键

 

可以通过如下程序试验：


 
from tkinter import *

 
root =Tk()

 
def callback(event):

print(event.keysym)

print(event.keycode)

 
frame = Frame(root, width=200, height=200)

frame.bind("<Key>", callback) #组件想要响应键盘事件，组件必须获得焦点，组件才会响应键盘来的消息。因为一个窗口可以有很多组件，键盘一次敲击不知道给哪个组件。

frame.focus_set() #通过focus_set方法获得焦点。也可以设置Frame的takefocus选项为True，然后使用Tab将焦点转移上来

frame.pack()

 
mainloop()
/***************************/

鱼c笔记——Python的GUI编程（十六）：Tkinter的三大布局管理器pack、grid和place

#pack
#grid
#place


什么是布局管理器：管理我们组件如何排列的东西

 

Tkinter为我们提供了三个布局管理器：pack, grid和place

pack, grid和place均用于管理同在一个父组件下的所有组件的布局，其中：

pack是按添加顺序排列组件

grid是按行列形式排列组件

place则允许程序员指定组件的大小和位置

 

何时使用pack管理器？

对比grid管理器，pack更适用于少量组件的排列，但它在使用上更加简单（就像前面的所有例子中，展示一个组件我们一般都直接使用.pack()方法）。如果你需要创建相对复杂的布局结构，那么建议是使用多个框架（Frame）结构构成，或者使用grid管理器实现。

注意：不要在同一个父组件中混合使用pack()和grid()，因为Tkinter无法确定首先使用哪个布局管理器。

 

我们常常会遇到的一种情况是将一个组件放到一个容器组件中，并填充整个父组件。下面举个生成一个Listbox组件并将它填充到root窗口中：


 
from tkinter import *

 
root = Tk()

 
listbox = Listbox(root)

listbox.pack(fill=BOTH, expand=True)

#fill选项是填充整个父组件，expand选项是拉伸时依旧填满

 
for i in range(10):

listbox.insert(END, str(i))

 
mainloop()

其中，fill选项是告诉窗口管理器该组件将填充整个分配给它的空间，BOTH表示同时横向和纵向扩展，X表示横向，Y表示纵向。expand选项是告诉窗口管理器将父组件的额外空间也充满。

 

默认下，pack是将添加的组件一次纵向排列


 
from tkinter import *

 
root = Tk()

 
Label(root, text='red', bg='red', fg='white').pack(fill=X) #fill选项是设置横向填充

Label(root, text='red', bg='green', fg='black').pack(fill=X)

Label(root, text='red', bg='blue', fg='white').pack(fill=X)

#整体是纵向填充

 
#Label(root, text='red', bg='red', fg='white').pack(side=LEFT) 如果想将组件整体横向排列，可以设置side选项

 
mainloop()

 

 

 

何时使用grid管理器？

grid管理器可以说是Tkinter这三个布局管理器中最灵活多变的。如果你只希望学习使用一个布局管理器，那么grid绝对是首选。当你在设计对话框的时候，使用grid尤其便捷。使用一个grid就可以简单的实现你用很多个框架和pack搭建起来的效果。

 

使用grid排列组件，只要告诉它你想要组件放置的位置（行/列，row选项指定行，column选项指定列）。此外你并不用提前指出网格（grid分布给组件的位置称为网格）的尺寸，因为管理器会自动计算。

 

设置一个简单的登录界面：


 
from tkinter import *

 
root = Tk()

 
Label(root, text='用户名').grid(row=0, column=0, sticky=W) #sticky选项设置组件朝向

Label(root, text='密码').grid(row=1, column=0, sticky=W)

 
Entry(root).grid(row=0, column=1)

Entry(root, show='*').grid(row=1, column=1)

 
mainloop()

 

用几个网格来放置一个组件，可以使用rowspan和columnspan实现跨行跨列的功能：


 
from tkinter import *

 
root = Tk()

 
Label(root, text='用户名').grid(row=0, column=0, sticky=W)

Label(root, text='密码').grid(row=1, column=0, sticky=W)

 
photo = PhotoImage(file="D:\u.gif") #只能是.gif格式

Label(root, image=photo).grid(row=0, column=2, rowspan=2, padx=5, pady=5) #rowspan选项设置了跨行，现在photo组件可以显示0,1两行了。padx，pady设置了边距，使图片文字不挨在一起

 
Entry(root).grid(row=0, column=1)

Entry(root, show='*').grid(row=1, column=1)

 
def test():

print('提交成功')

 
Button(root, text='提交', width=10, command=test).grid(row=2, columnspan=3, pady=5) #column默认是0

 
mainloop()

 

 

如何使用place管理器：

通常情况下不建议使用place布局管理器，因为对比起pack和grid，place要做更多的工作。不过存在即合理，place在一些特殊的情况下可以发挥妙用，甚至是pack和grid无法代替。

 

将子组件显示在父组件的正中间


 
from tkinter import *

 
root = Tk()

 
def callback():

print('点到我了')

 
Button(root, text='点我', command=callback).place(relx=0.5, rely=0.5, anchor=CENTER) #relx和rely是相对父组件的位置。0是最左边，0.5是正中间，1是最右边

 
mainloop()

 

 

在某种情况下，你希望一个组件能够覆盖另一个组件。下面使用一个按钮覆盖一个Label图片的例子


 
from tkinter import *

 
root = Tk()

 
photo = PhotoImage(file="D:\u.gif")

Label(root, image=photo).pack()

 
def callback():

print('点到我了')

 
Button(root, text='点我', command=callback).place(relx=0.5, rely=0.5, anchor=CENTER) #relx和rely是相对父组件的位置。0是最左边，0.5是正中间，1是最右边

 
mainloop()

relx和rely选项指定的是相对于父组件的位置，范围是00~1.0

relheight和relwidth选项则是指定相对于父组件的尺寸


 
from tkinter import *

 
root = Tk()

 
Label(root, bg='red').place(relx=0.5, rely=0.5, relheight=0.75, relwidth=0.75, anchor=CENTER) #relheight和relwidth是设置调用place的子组件相对于父组件的高度和宽度

Label(root, bg='yellow').place(relx=0.5, rely=0.5, relheight=0.5, relwidth=0.75, anchor=CENTER)

Label(root, bg='green').place(relx=0.5, rely=0.5, relheight=0.25, relwidth=0.75, anchor=CENTER)

 
mainloop()

还有x和y选项用于设置偏移（像素），如果同时设置relx(rely)和x(y)，那么place将优先计算relx和rely，然后再实现x和y指定的偏移值。

 

 

pack的方法

注：下边方法适用于所有组件

pack(**options)

--下方详细列举了各个选项的具体含义和用法

 

 

anchor：

--控制组件在pack分配的空间中的位置

--N, NE, E, SE, S, SW, W, NW或CENTER来定位（EWSN表示东南西北）

--默认值是CENTER

 

expand：

--指定是否填充父组件的额外空间

--默认值是False

 

fill：

--指定填充pack分配的空间

--默认值是NONE，表示保持子组件的原始尺寸

--还可以使用的值有：X（水平填充），Y（垂直填充）和BOTH（水平和垂直填充）

 

in_：

--将该组件放到该选项指定的组件中

--指定的组件必须是该组件的父组件

 

ipadx：

--指定水平方向上的内边距

 

ipady：

--指定垂直方向上的内边距

 

padx：

--指定水平方向上的外边距

 

pady：

--指定垂直方向上的外边距

 

side：

--指定组件的放置位置

--默认值是TOP

--还可以设置的值有：LEFT，BOTTOM，RIGHT

 

 

pack_configure(**options)

--跟pack()一样

 

pack_forget()

--将组件从屏幕中“删除”

--并没有销毁该组件，只是看不到了

--可以通过pack或其他布局管理器显示已“删除”的组件

 

pack_info()

--以字典的形式返回当前的pack的选项

 

pack_propagate(flag)

--如果开启，父组件会自动调节尺寸以容纳所有子组件

--默认值是开启（flag=True）

--该方法仅适用于父组件

 

pack_slaves()

--以列表形式返回该组件的所有子组件

--该方法仅适用于父组件

 

 

 

grid的方法：

注：下边方法适用于所有组件

grid(**options)

--下面列举了各个选项的具体含义和用法

column：

--指定组件插入的列（0表示第一列）

--默认值是0

 

columnspan：

--指定用多少列（跨列）显示该组件

 

in_：

--将该组件放到该选项指定的组件中

--指定的组件必须是该组件的父组件

 

 

ipadx：

--指定水平方向上的内边距

 

ipady：

--指定垂直方向上的内边距

 

padx：

--指定水平方向上的外边距

 

pady：

--指定垂直方向上的外边距

 

row：

--指定组件插入的行（0表示第一行）

 

rowspan：

--指定用多少行（跨行）显示该组件

 

sticky：

--控制组件在grid分配的空间中的位置

--可以使用N，E，S，W以及他们的组合来定位

--使用加号（+）表示拉长填充，例如N+S表示将该组件垂直拉长填充网格，N+S+W+E表示填充整个网格

--不指定该值则居中显示

 

 

grid_bbox(column=None, row=None, col2=None, row2=None)

--返回一个四元组描述该组件所在的限定矩形

--如果指定column和row参数，则返回该位置(column, row)的组件的限定矩形的描述

 

grid_columnconfigure(index, **options)

--设置列的属性

--注意：设置的是该组件所拥有的grid序列

--可以设置的选项及含义如下：

minsize：

--指定该列的最小宽度

 

pad--指定该列中最大网格的水平边距

 

weight：

--指定列与列之间的相对距离

--默认值是0

--说明：初创建窗口的时候，grid会自动根据组件的尺寸分配窗口的尺寸，当你拉伸窗口的尺寸就会有空白显示出来。这个选项正是指定列与列之间是否填充空白，默认是不填充的。另外，该选项的值是指定填充空白的倍数，例如weight=2的列会比weight=1的列填充多一倍的空白，所以需要平均填充的话，只需要所有的列都设置为weight=1即可。

 

grid_configure(**options)

--跟grid()一样

 

grid_forget()

--将组件从屏幕中“删除”

--并没有销毁该组件，只是看不到了

--可以通过grid或其他布局管理器显示已“删除”的组件，但该组件所在网格的选项设置不会恢复

 

grid_info()

--以字典的形式返回当前grid的选项

 

grid_location(x, y)

--返回位于（或接近）给定坐标（x, y）的网格位置

--返回值是一个2元组表示网格对应的（列， 行）

 

grid_propagate(flag)

--如果开启，父组件会自动调节尺寸以容纳所有子组件

--默认值是开启（flag=True）

--该方法仅适用于父组件

 

grid_remove()

--跟grid_forget()一样，但恢复的时候会记住该组件所在网格的选项设置

 

grid_rowconfigure(index, **options)

--设置行的属性

--注意：设置的是该组件所拥有的grid的行

--可以设置的选项及含义如下：

minsize：

--指定该行的最小高度

 

pad：

指定该列中最大网格的垂直边距

 

weight：

--指定行于行之间的相对距离

--默认值是0

 

 

grid_size()

--返回该组件所拥有的grid的尺寸

--返回值是一个2元组，表示（列，行）分别的网格数

 

grid_slaves(row=None, column=None)

--以列表的形式返回该组件的所有子组件

--该方法仅适用于父组件

 

 

 

place的方法

注：下边的方法适用于所有的组件

 

place(**options)

--下方列举了各个选项的含义和用法

 

anchor：

--控制组件在place分配的空间中的位置

--N, NE, E, SE, S, SW, W, NW或CENTER来定位（EWSN表示东南西北）

--默认值是NW

 

bordermode：

--指定边框模式（INSIDE或OUTSIDE）

--默认值是INSIDE

 

height：

--指定该组件的高度（像素）

 

in_：

--将该组件放到该选项指定的组件中

--指定的组件必须是该组件的父组件

 

relheight：

--指定该组件相对于父组件的高度

--取值范围是0.0~1.0

 

relwidth:

 

--指定该组件相对于父组件的宽度

--取值范围是0.0~1.0

 

relx：

 

--指定该组件相对于父组件的水平位置

--取值范围是0.0~1.0

 

rely：

 

--指定该组件相对于父组件的垂直位置

--取值范围是0.0~1.0

 

width：

--指定该组件的宽度（像素）

 

x：

--指定该组件的水平偏移位置（像素）

--如果同时指定了relx选项，优先实现relx选项

 

y：

 

--指定该组件的垂直偏移位置（像素）

--如果同时指定了rely选项，优先实现rely选项

 

 

place_configure(**options)

--跟place()一样

 

place_forget()

--将组件从屏幕中“删除”

--并没有销毁该组件，只是看不到了

--可以通过place或其他布局管理显示已“删除”的组件

 

place_info()

--以字典的形式返回当前place的选项

 

place_slaves()

--以列表的形式返回该组件的所有子组件

--该方法仅适用于父组件

 

slaves()

--跟place_slaves()一样

ipadx：

--指定水平方向上的内边距

ipadx：

--指定水平方向上的内边距

/**************************/


鱼c笔记——Python的GUI编程（十七）：Tkinter的标准对话框模块messagebox 、filedialog 和 colorchooser

#messagebox
#filedialog
#colorchooser


Tkinter为我们提供了三种标准对话框模块，他们分别是：

messagebox

filedialog

colorchooser



注：这三个模块原来是独立的，分别是tkMessageBox、tkFileDialog和tkColorChooser，需要导入才能使用。在Python3之后，这些模块全部被归纳到Tkinter模块的麾下。



Messagebox（消息对话框）

下文为你列出了使用messagebox可以创建的所有标准对话框样式：

from tkinter import messagebox
#import tkinter.messagebox
from tkinter import *
 
print(messagebox.askokcancel('messagebox', 'Demo one'))
#有返回值，点‘确定’返回True，点‘取消’返回False。后序可以有对返回值的操作进行下一步
 
mainloop()


使用函数和对话框样式

askokcancel(item, message, options)



askquestion(title, message, options)



askretrycancel(title, message, options)



askyesno(title, message, options)



showerror(title, message, options)



showinfo(title, message, options)



showwarning(title, message, options)







参数

所有的这些函数都有相同的参数：

----title参数设置标题栏的文本

----message参数设置对话框的主要内容，可以使用'\n'来进行换行

----options参数可以设置的选项和含义如下

default

--设置默认的按钮（也就是按下回车响应的那个按钮）

--默认是第一个按钮（像‘确定’，‘是’或‘重试’）

--可以设置的值根据对话框的不同可以进行选择：CANCEL、IGNORE、OK、NO、RETRY或YES



icon

--指定对话框显示的图标

--可以指定的值有：ERROR、INFO、QUESTION或WARNING

--注意：不能自己指定自己的图标（不可自定义图标）



parent

--如果不指定该选项，那么对话框默认显示在根窗口上

--如果想要讲对话框显示在子窗口w上，那么可以设置parent=w





返回值

askokcancel()、askretrycancel()和askyesno()返回布尔类型的值：

--返回True表示用户点击了‘确定’或‘是’按钮

--返回False表示用户点击了‘取消’或‘否’按钮

askquestion()返回‘yes’或‘no’字符串表示用户点击了‘是’或‘否’按钮

showerror()、showinfo()和showwarning()返回‘ok’表示用户按下了‘是’按钮







filedialog（文件对话框）

当你的应用程序需要使用打开文件或保存文件的功能时，文件对话框显得尤为重要。emmm，印象里Java好像也有个组件还是函数可以几行实现。

#from tkinter import filedialog
import tkinter.filedialog
from tkinter import *
 
root = Tk()
 
def callback():
    fileName = filedialog.askopenfilename()
    print(fileName)
 
Button(root, text='打开文件', command=callback).pack()
 
mainloop()

filedialog模块提供了两个函数：askopenfilename(**options)和asksaveasfilename(**options)，分别用于打开文件和保存文件。



参数

两个函数可供设置的选项是一样的，下面列举了可用选项及含义：

defaultextension

--指定文件的后缀

--例如：defaultextension='.jpg'，那么当用户输入一个文件名'Python'的时候，文件名会自动添加后缀为'Python.jpg'

--注意：如果用户输入文件名包含后缀，那么该选项不生效



filetypes

--指定筛选文件类型的下拉菜单选项

--该选项的值是由二元组构成的列表

--每个二元组是由（类型名，后缀）构成，例如：filetypes=[('PNG', '.png'), ('JPG', '.jpg'), ('GIF', '.gif')]







initialdir

--指定打开保存文件的默认路径

--默认路径是当前文件夹



parent

--如果不指定该选项，那么对话框默认显示在根窗口上

--如果想要将对话框显示在子窗口w上，那么可以设置parent=w



title

--指定文件对话框的标题栏文本





返回值

1.如果用户选择了一个文件，那么返回值是该文件的完整路径

2.如果用户点击了取消按钮，那么返回值是空字符串









colorchooser（颜色对话框）

颜色对话框提供了一个友善的界面让用户选择需要的颜色。

from tkinter import colorchooser
from tkinter import *
 
root =Tk()
 
def callback():
    fileName = colorchooser.askcolor()
    print(fileName)
 
Button(root, text='选择颜色', command=callback).pack()
 
mainloop()

colorchooser模块提供了一个函数askcolor(color, option=value, ...)



参数

color

--要显示的初始的颜色(下图四个红箭头指的地方)

--默认颜色是浅灰色（light gray）





parent

--如果不指定该选项，那么对话框默认显示在根窗口上

--如果想要将对话框显示在子窗口w上，那么可以设置parent=w



title

--指定颜色选择器标题栏的文本

--默认标题是“颜色”





返回值

1.如果用户点击的‘确定’按钮，返回值是一个二元组(triple, color)，其中的triple是一个三元组(R, G, B)--其中R, G, B的范围是[0, 255]（就是该颜色的RGB颜色），第二个参数选中颜色的16进制的值

2.如果用户点击的‘取消’按钮，返回值是（None, None）

/***************************/


鱼c笔记——Python的GUI编程（三）：Tkinter的三个组件Checkbutton、Radiobutton和Labelframe
#Checkbutton
#Radiobutton
#Labelframe

内容摘要：

Checkbutton、Radiobutton和Labelframe的基本用法

pack的anchor属性、fill属性

通过修改Radiobutton的indicatoror属性改变默认的圆形勾选框

 

 

Checkbutton多选框。

Radiobutton单选框

 

先感受一下Checkbutton的用法：


 
from tkinter import *

 
root = Tk()

 
v = IntVar() #需要一个tk变量，用于表示按钮是否被选中。默认情况下，未选中是0，选中是1

 
c = Checkbutton(root, text='测试一下', variable=v) #variable用来表示按钮的状态（是否被按下）

c.pack()

 
l = Label(root, textvariable=v) #为了更直观的看出选中和未选中v的表现状态，可以将其显示在Label标签里

l.pack()

 
mainloop()

 

下面是一个翻牌子的程序：


 
from tkinter import *

 
root = Tk()

 
GIRLS = ['西施', '貂蝉', '王昭君', '杨玉环']

 
v = [] #每一个按钮都需要一个存放变量的，所以这里用列表。后面用循环来添加

 
for girl in GIRLS:

v.append(IntVar())#每一次都需要一个整形的tk变量用于每个存放按钮的状态，再追加到列表里去

b = Checkbutton(root, text=girl, variable=v[-1]) #依次显示每个girl的名字。每一次都要拿到最后一个元素，因此是-1

b.pack(anchor=W) #所有的Checkbutton左对齐。anchor用于指定显示位置，可以设置为N W S E NW WS SE EN（东南西北英文缩写） CENTER九个不同的值

 
mainloop()

 

 

 

 

Radiobutton的用法和Checkbutton的用法基本一致，唯一的不同是Radiobutton要实现单选的效果，即互斥的效果。同一组内，所有的Radiobutton只能共享一个variable这个选项，并且要设置不同的value的值。


 
from tkinter import *

 
root = Tk()

 
v = IntVar() #多个按钮只需要一个变量

 
#variable只能是同一个变量。value的值必须不同才能互斥

Radiobutton(root, text='one', variable=v, value=1).pack(anchor=W)

Radiobutton(root, text='two', variable=v, value=2).pack(anchor=W)

Radiobutton(root, text='three', variable=v, value=3).pack(anchor=W)

#原理是每一次点中一个按钮，会把value的值给v，给这个v说明点中了。再和其他的value值对比，都不是2，因此不显示

 
mainloop()

 

当存在多个选项的时候，使用循环会更加简洁。


 
from tkinter import *

 
root = Tk()

 
v = IntVar() #多个按钮只需要一个变量

 
LANGS = [

('Pyhton', 1),

('Perl', 2),

('Ruby', 3),

('Lua', 4)]

 
v = IntVar()

v.set(1)

 
for lang, num in LANGS:

b = Radiobutton(root, text=lang, variable=v, value=num, indicatoron=False) #改变前面的小圆点为按钮形式

b.pack(fill=X) #X是横向填充，Y是纵向填充

 
mainloop()

 

 

 

Labelframe标签框架。实际上是Frame框架的进化版，从形态上来说就是添加了Label的Frame。有了它，Checkbutton和Radiobutton的分组就变得简单了。


 
from tkinter import *

 
root = Tk()

 
group = LabelFrame(root, text='最好的脚本语言是：', padx=5, pady=5)

group.pack(padx=10, pady=10)

 
LANGS = [

('Pyhton', 1),

('Perl', 2),

('Ruby', 3),

('Lua', 4)]

 
v = IntVar()

 
for lang, num in LANGS:

b = Radiobutton(group, text=lang, variable=v, value=num)

b.pack(anchor=W)

 
mainloop()

/**************************/






