欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python GUI设计 tkinter 笔记

程序员文章站 2022-04-12 09:46:45
...
#  《Python GUI设计 tkinter菜鸟编程》学习笔记,可直接执行代码
#  排版混乱,可设置Tab缩进为2个空格查看

from tkinter import *

# 创建窗口实例
root = Tk()
#也可以用 import tkinter  ;root = tkinter.Tk()的形式,但所有对象的方法前都要加tkinter.

# 设置窗口标题
root.title("GUI_NOTE")

# 窗口大小
root.geometry("300x160")
#窗口居中的方法:
width = root.winfo_screenwidth()  #获取屏幕宽度
height = root.winfo_screenheight()  #获取屏幕高度
w = 300 #程序窗口的宽
h = 160
x = (width-w)/2
y = (height-160)/2
root.geometry("%dx%d+%d+%d" %(w,h,x,y))


# 窗口颜色
root.configure(bg='yellow')

"""
窗口相关方法                                      说明
title()                                    设置窗口标题
geometry("宽x高+x轴偏移+y轴便宜")           设置窗口大小和设置窗口在屏幕的位置
maxsize(宽,高)                             拖拽时可以设置窗口最大的宽和高
minsize(宽,高)                             拖拽时可以设置窗口最小的宽和高
configure(bg="color")                      设置窗口背景颜色,也可以用16进制表示,详细查RGB色彩表
resizable(True,True)                       设置是否更改窗口大小,第一个参数为宽,第二个为高;若固定窗口可以resizable(0,0)
state("zoomed")                            最大化窗口
iconify()                                  最小化窗口
iconbitmap("xx.ico")                       更改默认窗口图标
"""

# widget :控件、组件或部件,窗口建立后下一步创建控件


#---------------------------------------标签----------------------------------------

# 标签Label:  Lable(父对象,options,....)父对象为窗口容器,option为可选参数:
"""
(1)	anchor:如果空间大于标签时,控制标签位置,默认为center居中,n,ne,e,se,s,sw,w,nw(8个方向顺时针)
(2)	bg:背景颜色
(3)	bd:标签边界宽度,默认为1
(3)	fg:前景色彩(即标签颜色或文字颜色)
(4)	font:可选择字型样式和大小font参数包含以下内容(文本顺序写入,空格分隔;或者输入元组):
					1.字形:如helvetica、times等可以在word内查询
					2.大小:单位是像素(随着字体大小变化width、height也跟着联动变大变小)
					3.weight:如 bold、normal(黑体、标准)
					4.slant:只有italic和roman(倾斜)
					5.underline:例如True、False (下划线)
					6.overstrike:例如True、False	(一种HTML排版 不懂)
(5)	height:标签高度,单位是字符(即文本框高度)
(6)	image:标签以图片的方式呈现
(7)	text:标签内容,用换行符分行
(8)	textvariable:可以设置标签以变量的方式显示
(9)	underline:可以设置第几个文字有下划线,从0开始,默认为-1,表示无下划线
(10)width:标签宽度,单位是字符(即文本框宽度)
(11)wraplength:文本到多少宽度后换行,单位像素。
(12)justify:在多行的文本中设置最后一行的位置默认为center;left、right
(13)relief:可以控制标签的边框,可以应用在许多widget控件上,默认relief=FLAT;groove、raised、ridge、solid、sunken
(14)padx、pady:设置标签文字左右和上下边界与标签区间的x轴的距离(就是文字和“标签边框”的距离,不是和窗口的距离)
(15)compound:设置标签内图片和文字时彼此的位置关系,例如compound="lift"图像靠左,right,top,bottm,center(文字覆盖上面)
在设计程序时,可以将上面	参数作为属性设置
"""
label=Label(root,text="I like tkinter",bg='red',anchor="nw",fg="blue",height=3,
      width=14,font=('times 20 normal'),relief='raised')	#Label方法L必须大写
label.pack()	#.pack() 包装窗口的widget控件和定位窗口对象
"""	直接label=Label().pack()窗口效果一样,但因为前面赋予了变量给label所以对象类型已经非
		tkinter.Label,所以不建议合并一起修改;"""

#可以用photoimage()方法建立图像对象
imagebj = PhotoImage(file="xxx.png")	#Label(root,image=imagebj)用图片作为标签
# 让程序持续运行,并进入等待与处理窗口事件(一般放在程序最后一行)
root.mainloop()



#	config():widget的共同方法,更新或者补充widget属性的方法,用法和参数与label一样:

counter = 0 #计数的全局变量
def run_counter(digit):
	"""一个计算器"""
	def counting():
		global counter  # global 使用全局变量
		counter += 1
		digit.config(text=str(counter))	#用于更新或设置widget控件属性
		digit.after(1000,counting)  #隔一秒后调用counting
	counting()

root2 = Tk()
root2.title("root2")
digit=Label(root2,bg="yellow",fg="blue",height=3,width=10,font=("helvetic 20 bold"))
digit.pack()
run_counter(digit)	#	调用run_counter函数	
print(digit.keys())	#	keys()是widget的共同方法,可以打印Label()方法内所有的参数

digit.mainloop()

#		separator() 	分隔线,P30


#-----------------------------------窗口控件配置管理员-----------------------------------
"""在GUI设计中有三种方法包装和定位各组件在容器或窗口内的位置,这三种方法称为窗口控件管理员:
		(1):pack()方法 ; (2):grid()方法 ;  (3):place()方法"""

"""
一、pack()方法使用相对位置概念,控件的正确位置有pack方法自动完成,具体参数:

1.side:可以设置垂直或水平配置控件,默认为由上到下(TOP);由下往上(BOTTOM),
			 由左往右排列(LEFT),由右往左排列(RIGHT),多个控件还可以混合多种参数。

2.fill:参数告诉pack管理程序,设置控件填满所分配容器区间的方式,fill=X表示控件填满所分配的X轴不留白
				fill=Y表示填满Y轴,fill=BOTH表示控件可以填满所有分配的空间,默认为NONE表示保持原大小。

3.padx/pady:参数设定控件边界与容器的距离或是控件边界之间的距离,默认窗口下距离是1像素,表示
						当前控件与其他控件或容器边界的X轴和Y轴的距离

4.ipadx/ipady:参数可以控制标签文字与标签容器的XY的轴间距(就是文字与控件的距离)

5.anchor:设定widget控件在窗口总的位置,概念与标签中的anchor参数相似,区别在于此处是控件相对于
					容器的位置,默认为center;N,NE,E,SE,S,SW,W,NW(8个方向顺时针,大写)

6.expand:参数设定widget控件是否填满额外的父容器空间,默认为False(或0),True或1表示填满(拉伸窗口填满)。

side、fill、expand参数相互影响
"""
#	pack示例:
pack_ = Tk()
pack_.title("pack方法")
lab1 = Label(pack_,text="明志科技大学",bg="lightyellow")
lab2 = Label(pack_,text="长庚大学",bg="lightgreen")
lab3 = Label(pack_,text="长庚科技大学",bg="lightblue")

lab1.pack(side=LEFT,fill=Y)	#	从左开始排泄,然后占满Y轴
lab2.pack(fill=X,padx=6)	#	默认从上往下,然后占满X轴,与容器或控件边框的X轴间距设置为6
lab3.pack(fill=BOTH,expand=True)	#	默认从上往下,XY轴全部占满,另外填充额外父容器空间。
print(pack_.pack_slaves())	#打印所有widget控件对象

#	!!!!pack() 参数值不需要双引号和Label参数不同,同时注意大小写,基本全部为大写
pack_.mainloop()


"""
pack()为py tkinter中的一个类,所以他提供以下方法:
1.slaves():传回所有widget控件对象(不知道为什么和上面不一样)
2.forget():隐藏widget控件,可以用pack(option,..)复原显示
3.info():传回pack选项的对应值
4.location(x,y):传回词典是否在单元格内,如果是 传回左边,如果不是传回(-1,-1)
5.size():传回widget控件大小
6.propagate(boolean):参数是True表示父窗口大小由控件决定,默认为True

"""
#	grdi()实现建立色彩标签:
color = Tk()
color.title("颜色")

colors = ["red","orange","yellow","green","blue","purple"]

r=0
for c in colors:
	Label(color,text=c,relief="groove",width=20).grid(row=r,column=0)
	Label(color,bg=c,relief="ridge",width=20).grid(row=r,column=1)
	r += 1
[5]
color.mainloop()
"""
二、	grid()方法:是一种格状或类始于excel电子表格的包装和定位窗口组件的方法,具体参数:

1.row/column:相当于二维表格的行和列的意思(相同列的宽度根据当前列中宽度最大的,小的居中对齐);

2.columnspan:将某行的多个列的标签位置合并,xx.grid(row=0,column=1,columnspan=2)合并(0,1)和(0,2)

3.rowspan:将某列的多个行的的标签合并;

4.padx/pady:各控件间的距离,单位像素。

5.sticky:参数功能类似于anchor但只能设定N/S/W/E(上下左右),但sticky参数可以通过组合使用:
				 sticky=N+S:可以拉长高度让控件在顶端和低端对齐
				 sticky=W+E:可以拉长宽度让控件左边和右边对齐
				 sticky=N+S+E:可以拉长高度让控件在顶端和低端对齐,同时切齐右边
				 sticky=N+S+W:可以拉长高度让控件在顶端和低端对齐,同时切齐左边
				 sticky=N+S+W+E:可以拉长高度让控件在顶端和低端对齐,同时切齐左右两边
"""

"""
rowconfigure()和columnconfigure():使用这两个方法设定第几个row或column的缩放比例:
rowconfigure(0,weight=1):		row 0的控件当窗口改变大小事时放比是1
columnconfigure(0,weight=1): column 0的控件当窗口改变大小时缩放比是1
"""
suofang = Tk()
suofang.title("缩放")

#	配合sticky参数使用,实现拉伸窗口时控件跟着扩展
suofang.rowconfigure(1,weight=1)
suofang.columnconfigure(0,weight=1)

lab1 = Label(suofang,text="Label_1",bg="pink")
lab1.grid(row=0,column=0,padx=5,pady=5,sticky=W)#修改为W+E拉伸窗口时同样会有扩展效果

lab2 = Label(suofang,text="Label_2",bg="lightblue")
lab2.grid(row=0,column=1,padx=5,pady=5)

lab3 = Label(suofang,bg="yellow")
lab3.grid(row=1,column=0,columnspan=2,padx=5,pady=5,sticky=N+S+W+E) #让上下左右对齐

suofang.mainloop()


"""
三、place()方法:直接指定将控件放在容器中的方法(使用绝对左边或相对坐标),具体参数:

1.x/y:直接指定控件位置,单位像素,左上角为(0,0)往右下角递增。

2.width/height:可以直接设定插入图像大小,单位像素

3.relx/rely:相对位置(相对于容器内的位置)值0.0~1.0,左上角两个参数值都是0

4.relwidth/relheitht:相对大小(相对于容器内的大小),值为0.0~1.0.

书上推荐使用spak和grid方法。
"""


#-----------------------------------功能按钮 Button----------------------------------
"""
Button(父对象,options,.....),具体参数:绝大部分参数与Label相同,下面几个特有的
1.highlightbackground:当功能按钮取得焦点时的背景颜色
2.highlightcolor:当功能按钮取得焦点时的颜色
3.command:单击功能按钮时,执行此方法。(执行相应函数)command=root.destroy(关闭root窗口,关闭程序),
					 quit(关闭py内部shell,但root窗口还在执行)
"""
def bColor(bgColor):
	root.config(bg=bgColor)

root =Tk()
root.title("按钮,变色")
root.geometry("300x200")

exitbtn = Button(root,text="exit",command=root.destroy)
bluebtn = Button(root,text="blue",command=lambda:bColor("blue"))
yellowbtn = Button(root,text="yellow",command=lambda:bColor("yellow"))

exitbtn.pack(anchor=S,side=RIGHT,padx=5,pady=5)
bluebtn.pack(anchor=S,side=RIGHT,padx=5,pady=5)
yellowbtn.pack(anchor=S,side=RIGHT,padx=5,pady=5)

root.mainloop()


#----------------------------------------文本框 Entry-----------------------------------------
"""
Entry(父对象,option,.....):可输入的单行的文本框,大部分参数与Label相同,下面列取几个特殊的:

1.command:当用户更改内容时,会自动执行此函数。
2.exportselection:如果执行选取时,所选字符串会自动输入值剪贴板,如果想要避免,可以设置为0。
3.highlightbackground:当文本框获取焦点时的背景颜色(鼠标对着时)
4.highlightcolor:当文本框获取焦点是的文字颜色
5.selectbackground:被选取时字符串背景颜色。
6.selectborderwidth:被选取时边界宽度,预设是1.
7.selectfroeground:被选取是字符串颜色。
8.show:显示输入字符,例shou='*',类似于输入密码显示*号。
9.state:输入状态,NORMAL表示可以输入,DISABLE则表示无法输入
10.textvariable:文字变量
11.xscrollcommand:在X轴使用滚动条。

Entry的方法:
1.get():获取当前Entry的字符串类容
2.insert(index,s):在Entry文本框内建立默认文字,s是插入的字符串,index为插入index的位置;
									通常作用在Entry()方法建立万文本框后。
3.delete(fast,last=None):删除Entry内从fast字符到last-1之间的字符,删除整个用delete(0,END)
4.eval():计算数学表达式函数,不能说是Entry的方法,是py通用函数,往括号内输入数学表达式字符串,输出结果。
"""
#创建一个获取输入框然后打印在pyshell上的函数
def printInfo():
	print("Account: %s\npassword: %s" % (accountE.get(),pwdE.get()))

Entry_=Tk()
Entry_.title("文本框")

msg = "欢迎登录XXXXXX"
logo = Label(Entry_,text=msg)
accountL = Label(Entry_,text="Account")
accountL.grid(row=1)										#tkinter会默认补上column=0
PwdL = Label(Entry_,text="Password")
PwdL.grid(row=2)

logo.grid(row=0,column=0,columnspan=2,pady=10,padx=10)	#最上面的标签
accountE = Entry(Entry_)
pwdE = Entry(Entry_,show="*")	#隐藏密码为*
accountE.insert(0,"请输入帐号")	#输入框内默认文字
pwdE.insert(0,"请输入密码")

accountE.grid(row=1,column=1)
pwdE.grid(row=2,column=1,pady=10)



loginbtn = Button(Entry_,text="Login",command=printInfo)	#按钮运行上面的打印函数
loginbtn.grid(row=3,column=0,sticky=W,pady=5)
quitbtn = Button(Entry_,text="Quit",command=root.quit)		#按钮退出py程序
quitbtn.grid(row=3,column=1,sticky=W,pady=5)

Entry_.mainloop()


#-----------------------------------变量类别--------------------------------------
"""
想要更改将widget内容以变量的方式赋予可以用textvarsible,但要借组TK模块内的变量类别:
x = IntVar()				整型变量,默认是0
x = DoubleVar()			浮点型变量,默认是0.0
x = StringVar()			字符串变量,默认是""
x = BooleanVar()		布尔变量,True是1,False是0

可以使用.get()获取得变量内容,使用.set()方法设置变量内容

变量追踪函数trace():
XX.trace("w",函数):当变量XX被更改时,执行参数内函数(变动追踪)
XX.trace("r",函数):当变量XX被读取时,执行参数内函数(读取追踪)

之所以用textvariable=xx参数的目的,可以理解为将该对象以变量的型式赋予给某个变量,
然后这个变量就可以直接被xx.get()参数获取
"""
def callbacKW(*arges):
	xL.set(xE.get())			#不怎么明白这里的xE.get()怎么不算被读取

def callbacKR(*arges):
	print("warning:数据被读取!")

def hit():
	print("读取数据:",xE.get())

root = Tk()
root.title()

xE = StringVar()

entry = Entry(root,textvariable=xE)		#xE设为Entry的变量内容
entry.pack(pady=5,padx=10)
xE.trace("w",callbacKW)			#跟踪变量xE,若是被更改则执行函数callbacKW
xE.trace("r",callbacKR)			#跟踪变量xE,若是被读取则执行函数callbacKW

xL = StringVar()		#将xL变量赋予为字符串型,默认为""

#Entry的变量被更改时,会被追踪执行callbacKW,从而设定Label显示内容
label = Label(root,textvariable=xL)		
xL.set("同步显示")				#设定XL的初始显示,
label.pack(pady=5,padx=10)

#按钮执行函数hit,会引发变量被读取,而执行函数callbacKR
btn = Button(root,text="读取",command=hit)		
btn.pack(pady=5)

root.mainloop()


#	简易计算器的设计:

#执行计算并显示计算结果
def calculate():
	result = eval(equ.get())
	equ.set(equ.get()+"=\n"+str(result))

#	不断更新显示的计算式
def show(buttonString):
	content = equ.get()
	if content == "0":			#开始输入时,如果是0则不显示0
		content=""
	equ.set(content + buttonString)

#	功能键C,删除前一个字符
def backspace():
	equ.set(str(equ.get()[:-1]))

#	清除显示区
def clear():
	equ.set("0")

root = Tk()
root.title("简易计算器")

equ =  StringVar()
equ.set("0")

#	设计显示区
label = Label(root,width=50,height=4,relief="raised",anchor=SE,textvariable=equ)
label.grid(row=0,column=0,columnspan=4,padx=5,pady=5)

#	清除显示区按钮
clearButton = Button(root,text="C",fg="blue",width=10,command=clear)
clearButton.grid(row=1,column=0)

#	其他按钮
Button(root,text="DEL",width=10,command=backspace).grid(row=1,column=1)
Button(root,text="%",width=10,command=lambda:show("%")).grid(row=1,column=2)
Button(root,text="/",width=10,command=lambda:show("/")).grid(row=1,column=3)
Button(root,text="7",width=10,command=lambda:show("7")).grid(row=2,column=0)
Button(root,text="8",width=10,command=lambda:show("8")).grid(row=2,column=1)
Button(root,text="9",width=10,command=lambda:show("9")).grid(row=2,column=2)
Button(root,text="*",width=10,command=lambda:show("*")).grid(row=2,column=3)
Button(root,text="4",width=10,command=lambda:show("4")).grid(row=3,column=0)
Button(root,text="5",width=10,command=lambda:show("5")).grid(row=3,column=1)
Button(root,text="6",width=10,command=lambda:show("6")).grid(row=3,column=2)
Button(root,text="-",width=10,command=lambda:show("-")).grid(row=3,column=3)
Button(root,text="1",width=10,command=lambda:show("1")).grid(row=4,column=0)
Button(root,text="2",width=10,command=lambda:show("2")).grid(row=4,column=1)
Button(root,text="3",width=10,command=lambda:show("3")).grid(row=4,column=2)
Button(root,text="+",width=10,command=lambda:show("+")).grid(row=4,column=3)
Button(root,text="0",width=24,command=lambda:show("0")).grid(row=5,column=0,columnspan=2)
Button(root,text=".",width=10,command=lambda:show(".")).grid(row=5,column=2)
Button(root,text="=",width=10,bg="yellow",command=lambda:calculate()).grid(row=5,column=3)

root.mainloop()


#---------------------------------选项按钮与复选框-----------------------------------
"""
选项按钮:radiobutton(父对象,options,...),只能勾选一个选项,大部分参数一样,下面列取特殊的:

1.indicatoron:当此值为0时,可以建立盒子选项按钮。
2.textvariable:可以以变量方式显示选项按钮
3.variable;设置或取得目前选取的单选按钮,值类型一般为IntVar、StringVar。
4.value:选项的值,也相当于variable的值。(get()和set()可以获取和修改这个值)
"""
def printselection():
	print(cities[var.get()])	#	打印获取到的选项内容

root = Tk()
root.title("选项按钮")
#如果选项较多可以用字典的型式,也可以一个一个创建radiobutton选项。
cities = {0:"东京",1:"纽约",2:"巴黎",3:"香港"}	

var = IntVar()	#将变量var值设定为数值型
var.set(0)			#初始选项设为0
label = Label(root,text="选择你喜欢的城市",fg="blue",bg="lightyellow",width=30).pack()

#	indicatoron设置为0表示盒子选项按钮,不设置或设置其他值为普通选项按钮。
#	当选上相应的选项,value的值会赋予给变量var,然后执行函数printselection.
for val, city in cities.items():
	Radiobutton(root,text=city,indicatoron=0,width=30,variable=var,value=val,
							command=printselection).pack()

root.mainloop()

"""
复选按钮:Checkbutton(父对象,options,...),可以勾选对歌选项,参数和选项按钮大致相同

ertry一些常用方法:
.select_range(0,END):选取全部字符串
.select_clear():取消选取
.delete:删除文字
"""
def printInfo():
	selection = ""
	for i in checkboxes:
		if checkboxes[i].get() == True:				#	被选项框选取后对应的选项为True,未选上为False
			selection = selection + sports[i] + "\t"
	print(selection)

root = Tk()
root.title("复选按钮")

Label(root,text="请选择喜欢的运动",fg="blue",bg="lightyellow",width=30).grid(row=0)

sports = {0:"美式足球",1:"棒球",2:"篮球",3:"网球"}
checkboxes = {}		#	字典存放被选取的项目的状态(TRUE OR FALSE)
for i in range(len(sports)):
	checkboxes[i] = BooleanVar()			#	checkboxes[i]值的类型为布尔型,勾选后反馈Ture
	Checkbutton(root,text=sports[i],variable=checkboxes[i]).grid(row=i+1,sticky=W)

btn = Button(root,text="确定",width=10,command=printInfo)
btn.grid(row=i+1)
root.mainloop()


#------------------------------容器控件-----------------------------------------
"""
框架的概念:相当于一个容器控件,在设计复杂GUI时,可以将控件放在不同的框架内。
1.Frame(父对象,options,...):单纯生成框架,不含框架标签(文字)
2.LabelFrame(父对象,options,...):带标签的框架。
3.Toplevel(options,...):顶层窗口,生成一个新的窗口作为框架,不需要父对象,窗口属性部分参数法适用于它。

相关参数:(大致和上面一样)
1.width:框架宽度(或窗口宽度)
2.height:框架高度(或窗口高度)
3.labelAnchor:设置放置标签的位置。
4.relief:标签的外框样式(用得比较多)
#	一般创建框架,然后往框架内放置控件后,再进行包装和定位此框架。(frame可以省略父对象)
"""

def printInfo():
	selection = ""
	for i in checkboxes:
		if checkboxes[i].get() == True:				#	被选项框选取后对应的选项为True,未选上为False
			selection = selection + sports[i] + "\t"
	print(selection)

root = Tk()
root.title("复选按钮")
root.geometry('400x200')

labframe = LabelFrame(root,text="选择最喜欢的运动")		#创建带标签框架
sports = {0:"美式足球",1:"棒球",2:"篮球",3:"网球"}
checkboxes = {}		#	字典存放被选取的项目的状态(TRUE OR FALSE)
for i in range(len(sports)):
	checkboxes[i] = BooleanVar()			#	checkboxes[i]值的类型为布尔型,勾选后反馈Ture
	Checkbutton(labframe,text=sports[i],variable=checkboxes[i]).grid(row=i+1,sticky=W)
labframe.pack(ipadx=5,ipady=5,pady=10)	# 框架内所有控件做好后再包装此框架(好像不一定)

btn = Button(root,text="确定",width=10,command=printInfo)
btn.pack()
root.mainloop()


#------------------------------尺度条scale、spinbox--------------------------------
"""
Scale():通过移动尺度条产生某一范围的数字,特有参数如下:

1.command:使用或者更改数值时,自动运行该函数
2.digits:尺度数值,读取时需要用那个IntVar、Double、StringVar变量类型来读取
3.from_:尺度条范围值的初值。
4.to:尺度条范围值的末端值。
5.label:默认是没有标签的,赋予后水平尺度条标签在左上角,垂直在右上角。
6.length:默认100像素。
7.orient:尺度条默认是垂直,水平设置为HORIZONTAL
8.resolution:每次更改的数值,就是步长
9.tickinterval:尺度条的标记刻度。
10.troughcloro:滚动槽颜色
11.cariable:设置或取得目前选取的尺度值,类型通常为IntVar或StringVar(感觉和2配合)
12.width:对于垂直就是宽度,对于水平则是高度。

xx=askcolor():该方法调出色彩框选取色彩,返回一个元组,第一个元素为3个RGB,第二个元素为16进制色彩
"""
# 滚动设置窗口背景颜色示例:
def bgupdate(source):
	"""更改窗口背景颜色"""
	red = rSlider.get()			# 读取red的值(这里和上面不太一样,直接get()控件的对象)
	green = gSlider.get()
	bule = bSlider.get()
	print("R=%d,G=%d,B=%d" % (red, green, bule)) # 打印获取的颜色RGB
	myColor = "#%02x%02x%02x" % (red, green, bule)	# 将颜色转化为16进制字符串
	root.config(bg=myColor)				#设置窗口颜色

root = Tk()
root.title("更改背景窗口颜色")
root.geometry("360x240")

fm = Frame(root)
fm.pack()

rSlider = Scale(fm, from_=0, to=255, command=bgupdate) #设置scale控件在框架内,范围值和函数
gSlider = Scale(fm, from_=0, to=255, command=bgupdate)
bSlider = Scale(fm, from_=0, to=255, command=bgupdate)
gSlider.set(125)    #设置初始值
rSlider.grid(row=0,column=0)
gSlider.grid(row=0,column=1)
bSlider.grid(row=0,column=2)

root.mainloop()

"""
Spinbox():另一种输入控件,类始于Entry和Button的合体,可以用鼠标单击UP/DOWN来选择上下数值。:

1.format:格式化字符串
2.from_ / to : 数值的初始值和末端值
3.increment:每次单击UP/DOWM按钮的增值或者减值(步长)
4.repeatdelay:设置长安按钮数值变化的时间间隔,默认300ms
5.textvariable:设置一边凉方式显示
6.values:可以是元组或者其他序列值(给定数列值,按UP/DOWM来显示该数列,可以是字符串)
7.width:对于垂直就是宽度,对于水平则是高度。
8.wrap:单击UP/DOWM按钮可以重新开始
9.xscrollcommand:在x轴使用滚动条
"""
def printInfo():
	print(sp.get())

root = Tk()
root.title("Spinbox控件")
cities = ("新加波", "上海", "东京")

sp = Spinbox(root, values=cities, command=printInfo)  # 将cities作为UP/DOWN选项
# 也可以做成显示数值:
# sp = Spinbox(root, from_=0, to=10 , command=printInfo)
sp.pack(pady=10,padx=10)
root.mainloop()


#--------------------------------message 和 messagebox------------------------------------
"""
message():具体用法和Label差不多,方法也一致

messagebox():相当于弹出一个对话框,主要包含8种:

1.showinfo(title,message,options):显示一般消息。
2.showwarning(title,message,options):显示告警消息。
3.showwerror(title,message,options):显示错误消息。
4.askquestion(title,message,options):显示询问消息,若单击“是”按钮会传回“yes”,“否”按钮传回“no”。
5.askquestion(title,message,options):显示确定或取消消息,单击“确定”按钮传回“True”,"取消"传回“False”。
6.askquestion(title,message,options):显示是或否消息,单击“是”传回“True”,“否”传回“False”。
7.askquestion(title,message,options):显示是或否或取消,分别传回True、False、None。
8.askquestion(title,message,options):显示重试或取消,分布传回True、False。

上面对话框内参数基本相同,titles是对话框名称,message为内容,options为可选参数,可选主要有3个:
1.default constant:默认按钮是OK(确认),YES(是),Retry(重试),也可以更改此设定
2.icon(constant):可设置所显示的图标,有INFO、ERROR、QUESTION、WARNING 4种
3.parent(wedget):指出当对话框关闭时,焦点窗口将返回此父窗口。

!!最后注意,因为对话框是放在tkinter模块内的messagebox模块下,所以要使用这些默认对话框需要
    在程序开头增加导入 from tkinter import messagebox
"""
from tkinter import messagebox

def myMsg1():
	ret = messagebox.askretrycancel("test1","安装失败,再试一次")
	print("安装失败",ret)   #ret 为回传消息,根据这个回传值可以进行更多判定和执行方式

def myMsg2():
	ret = messagebox.askyesnocancel("test2","编辑完成,是或否或取消")
	print("编辑完成",ret)
root = Tk()
root.title("messagebox")
root.geometry("360x240")

Button(root, text="安装失败", command=myMsg1).pack()
Button(root, text="编辑完成", command=myMsg2).pack()
root.mainloop()


#-------------------------------------事件和绑定-----------------------------------------
#	tkinter最后一个指令.mainloop()就是让程序进入时间等待循环。
"""
	widget提供为事件的绑定处理机制语法如下:widget.bind(event,handler);其中widget是事件的来源,
	可以是root窗口,或者任意widget控件等,event为触发的事件如:鼠标单击,键盘等,handler为事件
	处理程序,相当于当event时间本触发时,运行相关的程序或函数。
列取相关鼠标事件:
<Button-1>:单击鼠标左键,鼠标光标相对空间位置会被存入时间对象的x和y变量。
<Button-2>:单击鼠标中键,鼠标光标。。。。。。。
<Button-3>:单击鼠标右键,。。。。。。。。
<Button-4>:鼠标滑轮向上滚动,。。。。。。。
<Button-5>:鼠标滑轮向下滚动,。。。。。。。
<Mition>:鼠标移动,。。。。。。
<B1-Motion>:拖拽,按住鼠标左键再移动,。。。。。。
<B2-Motion>:拖拽,按住鼠标中键再移动,。。。。。。
<B3-Motion>:拖拽,按住鼠标右键再移动,。。。。。。
<ButtinRelease-1>:放开鼠标左键,。。。。。。
<ButtinRelease-2>:放开鼠标中键,。。。。。。
<ButtinRelease-3>:放开鼠标游右键,。。。。。。
<Double-Button-1>:双击左键,。。。。。。
<Double-Button-2>:双击中建,。。。。。。
<Double-Button-3>:双击右键,。。。。。。
<Enter>:鼠标进入wiget控件
<Leave>:鼠标离开wiget控件

键盘事件:
<FocushIn>:键盘焦点进入widget控件
<FocusOut>:键盘焦点离开wiget控件
<Return>:按下Enter键,键盘上所有的键都可以本绑定。
<Key>:按下某键盘键,键值会被储存在event对象中传递
<Shift-Up>:按住Shift同时按下Up
<Alt-Up>:按住Alt同时按下Up
<Ctrl-Up>:按住Ctrl同时按下Up

控件事件:
<Configure>:更改Widet控件的大小和位置,新的控件大小的width与height会储存在event对象内
"""
def enter(event):									# !!必须要有参数event,因为事件会传递对象给此事件处理程序
 	x.set("鼠标进入Exit功能按钮")
def leave(event):
	x.set("鼠标离开Exit功能按钮")
def myMsg(event):
	print("YYYYY")
	ret = messagebox.askretrycancel("test1","确定要退出吗?")

root= Tk()
root.title("鼠标事件绑定")
root.geometry("300x180")

btn = Button(root,text="Exit",command=root.destroy) # 这里最后没有退出。
btn.pack(pady=20)
btn.bind("<Enter>",enter)			#鼠标进入EXIT区域自动触发Enter事件,从而触发处理程序entry()
btn.bind("<Leave>",leave)
btn.bind("<Button-1>",myMsg,add="+")	#如果要一个事件触多个处理程序,需要加入参数add="+"
# 程序会先执行bind() 绑定的程序,然后再执行button内command指定的程序

x = StringVar()
lab = Label(root,textvariable=x,bg="yellow",height=4,width=15,font=("times 12 bold"))
lab.pack(pady=30)

root.mainloop()
# 在框架内的键盘事件绑定需要先获取焦点,一般鼠标先点击框架区域才能获取键盘焦点
#	取消绑定:obj.unbind("<xxx>")

# 窗口管理程序:触发事件"WM_DELETE_WINDOW"可以用messagebox来绑定处理关闭窗口的事件例如:。
#	root.protocol("WM_DELETE_WINDOW",callback)  用.protocol()方法来添加这类型控件
def callback():
	res = messagebox.askretrycancel("OKCANCEL","结束或取消")
	if res ==True:
		root.destroy()
	else:
		return


#----------------------------------列表框Listbox和滚动条Scrollbar---------------------------
"""
Listbox(): 列表框,可以设置单选多选,大部分参数通用:

1.highlightcolor:当列表框获得焦点时的颜色
2.listvariable:以变量方式处理选项内容
3.selectbackground:被选去字符串的背景颜色
4.selectmode:可以决定有多少选项可以被选,以及鼠标拖拽如何影响选项。
							1.BROWSE:这是默认值,可以选择一个选项,如果选取一个选项同时拖拽鼠标,将造成选项
								最后的位置是被选取的项目位置。
							2.SINGLE:只能选择一个选项,可以用单击方式选取,不可以用拖拽方式更改所选的项目。
							3.MULTIPE:可以选择多个选项,单击项目可以切换是否选择该项目
							4.EXTENDED:单击第一个项目然后拖拽到最后一个项目,即可选择这个区间的一些列选项,
								单击可以选择一个项目,此时若是按住shift键兵单击另一个项目,可以选择区间。
5.xscrollcommand:在x轴使用滚动条。
6.yscrollcommand:在y轴使用滚动条。

#	建立列表框后可以用 insert(index,elements)方法为列表框建立插入项目,index是位置,最后可以用END,
	elements是插入项,可以是列表变量,或者单个字符串和以逗号分隔的多个字符串
	如果将END改为ACTIVE,表示是在目前被选选项前面加入一个项目,如果尚未选择此项,ACTIVE是0就是最前面
	lb.insert(ACTIVE,"orange","grapes","mango"):在前面补充建立三个项目

Listbox的基本操作方法:

1.size():传回列表项目的数量, lb.size(),列出选项总的数量
2.selection_set():选取特定索引项,例:lb.selection_set(0)表示默认选取第0个选项,(0,3)表示选取0~3
3.delete:删除特定索引项  lb.delete(1,3),表示删除1~3索引的项
4.get():传回指定索引项			lb.get(1,3),表示传回1~3索引的项名称,以元组的方式传回
5.curselection():传回选取项目的索引   a=lb.curselection()返回所选取项的索引
6.selection_include:检查指定索引项是否被选取  lb.selection_include(1)检查索引1是否被选,否False

"""
#Listbox 与事件绑定,当Listbox选取操作会产生<<ListboxSelect>>虚拟事件:

def itemAdded():											# 增加项目处理程序
	VarAdd = entry.get()								
	if (len(VarAdd.strip()) == 0):			# 没有增加不处理
		return
	lb.insert(END,VarAdd)								# 将Entry中的项加在列表框最后
	entry.delete(0,END)									# 添加完成后删除文本框内数据

#	新增的打印所以只能一个个删
def itemDelted():											
	index = lb.curselection()						# 传回被选取项的索引
	if(len(index) == 0):
		return
	lb.delete(index)										#	删除索引对应的项

def itemsSelected(event):							# 将被选取项 打印到shell上
	obj = event.widget 									#	获取事件对应的对象(就是获取事件发生的widget)
	indexs = obj.curselection()
	for index in indexs:
		print(obj.get(index))							#打印所选取索引对应的项
	print("------------")

root = Tk()
root.title("增加删除选项&虚拟绑定应用于多选")

entry = Entry(root)
entry.grid(row=0,column=0,padx=5,pady=5)

btnAdd = Button(root,text="增加",width=10,command=itemAdded)
btnAdd.grid(row=0,column=1,padx=5,pady=5)

lb = Listbox(root,selectmode=EXTENDED)	#	EXTENDED模式可以多选,拖拽
lb.insert(ACTIVE,"Banana","Watermelon","Pineappel","Orange","Grapes")	#插入初始
lb.bind("<<ListboxSelect>>",itemsSelected)		#	绑定虚拟事件,选定项目时执行函数
lb.grid(row=1,column=0,columnspan=2,padx=5,sticky=W)	#columnspan合并2个单元格

btnDel = Button(root,text="删除",width=10,command=itemDelted)
btnDel.grid(row=2,column=0,padx=5,pady=5,sticky=W)

root.mainloop()

#	滚动条设计:
"""	
	Scrollbar(父对象,options,...),Scrollbar控件除了可以应用在Listbox上也可以应用在Text和
	Cancas控件上,下面是比较重要的参数:
1.jump:每次短距离的拖拽滚动条时都会触发command方法,默认是0,如果是1则放开鼠标才触发command
2.orient:可以设置HORIZONTAL/VERTICAL 分别是水平/垂直,默认为垂直。
3.command:滚动条移动时所触发的方法
滚动条应该算是一个独立的控件,用其他控件的yscrollcommand参数来做连动
"""
root = Tk()
root.title("滚动条")

scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT,fill=Y)

#	创建Listbox,yscrollcommand 指向Scrollbar,set方法
#	yscrollcommand=scrollbar.set表示将listbox与滚动条做连动
lb = Listbox(root,yscrollcommand=scrollbar.set)
for i in range(50):
	lb.insert(END,"Line" + str(i))
lb.pack(side=LEFT,fill=BOTH,expand=True)
scrollbar.config(command=lb.yview)	#	执行lb的yview()方法

root.mainloop()


#----------------------下拉式列表OptionMenu和Combobox---------------------------

#	OptionsMenu(父对象,options,*values),其中*values是下拉列表,可以用元组的方式,也可以用","号分隔
def printSelection():
  print("The selection is : ",Var.get())	# 获取选项变量值

root = Tk()
root.title("OptionsMenu")
root.geometry("300x180")

omTuple = ("python","Java","C")
Var = StringVar(root)							#	留意此处root,不懂,试了下没有root照样运行

Var.set("python")									#	设定默认选项,也可以Var.set(OmTuple[0])
optionmenu = OptionMenu(root,Var,*omTuple)	#	用元组作为下拉菜单导入给
optionmenu.pack(pady=10)

btn = Button(root,text="print",command=printSelection)
btn.pack(pady=10,anchor=S,side=BOTTOM)
root.mainloop()

"""
组合框Combobox(父对象,options):这是tkinter.tkk的widgeton控件,常用options参数:
1.textvariable:可以设置Combobox的变量值。
2.value:Combobox的选项内容,内容以元组方式存在。

设置默认选项可以用.current()方法,当然也可以用set()
当Combobox选项有变动时,会产生虚拟<<ComboboxSelect>>事件,也可以用这个特性绑定处理方法
"""
from tkinter.ttk import *

def commboxSelection(event):
  labelVar.set(var.get())

root = Tk()
root.title("Combobox")
root.geometry("300x180")

var = StringVar()
cb = Combobox(root,textvariable=var)#	把cb对象以变量的形式赋予给var(后面可以直接var.get())
cb["value"] = ("python","Java","C","C#")	#	可以通过这种方式赋予列表,也可以直接在Combobox内
cb.current(0)																			#	设定默认选项
cb.bind("<<ComboboxSelected>>",commboxSelection)	#	绑定虚拟事件运行的程序
cb.pack(side=LEFT,padx=10,pady=10)

labelVar = StringVar()
label = Label(root,textvariable=labelVar)			#	将label被选项的值赋予给labelvar变量
labelVar.set(var.get())
label.pack(side=LEFT)

root.mainloop()



#--------------------------------容器PanedWindow和Notebook----------------------------
"""
PanedWindow:相当于面板是一个widget容器,和Frame框架不一样,建立在PanedWindow内的控件不需要再包装
						但建立在Frame内的控件需要包装,可以在PanedWindow内建立框架在建立控件,常用参数:
1.orient:面板配置的方向默认是水平HORIZONTAL,VERTICAL
2.width:面板整体宽度,没有默认值

add(child,options):用插入子控件来往容器内插入控件对象,child为插入的控件对象,可用用参数weight
weight:变化比例,表示拉伸窗口是每个容器的变化比,这个是tkk模块,必须先导入,1为比率为1:1
"""
from tkinter.ttk import *	# 因为使用了weight。

root = Tk()
root.title("容器PanedWindow")

pw = PanedWindow(orient=HORIZONTAL)			#	创建PanedWindow对象

leftframe = LabelFrame(pw,text="left pane",width=120,height=150)	#	框架父对象是pw容器
pw.add(leftframe,weight=2)		#	往容器内插入框架控件
middleframe = LabelFrame(pw,text="middle pane",width=120)
pw.add(middleframe,weight=2)
rightframe = LabelFrame(pw,text="right pane",width=120)	#	这里pw父对象可以省略,因为下面add加入
pw.add(rightframe,weight=1)			# 拉伸时比例为1

pw.pack(fill=BOTH,expand=True,padx=10,pady=10)
root.mainloop()
# 也可以往PanedWindow容器内插入其他控件,如label、entry等。

"""
Notebook:也是一个Widget容器控件,这个控件的特点是拥有许多选项卡,相当与子窗口(Notebook是ttk)
创建Notebook容器控件后,通过add(子对象,options)方法加入子选项卡,option参数如下:
1.compound:可以设置选项卡内同时含有图像和文字时彼此的关系
2.padding:可以设置Notebook和面板pane的额外控件
3.image:选项卡以图像方式呈现
4.state:可能值是normal、disabled、hidden,表示正常,无法被选取和隐藏
5.sticky:指出窗口面板的配置方式,n/s/e/w,表示方向
6.text:选项卡的名称
"""
from tkinter.ttk import *
from tkinter import messagebox

def msg():
	messagebox.showinfo("Notebook","欢迎使用Notebook")

root = Tk()
root.title("容器Notebook")
root.geometry("300x160")

notebook = Notebook(root)

frame1 = Frame()
frame2 = Frame()	#省略父对象,因为当整个框架做完后,会通过add加入到notebook容器内。

label = Label(frame1,text="Python")
label.pack(padx=10,pady=10)
btn = Button(frame2,text="help",command=msg)
btn.pack(padx=10,pady=10)

#	将框架控件插入到容器内
notebook.add(frame1,text="页次1")	
notebook.add(frame2,text="页次2")
notebook.pack(padx=10,pady=10,fill=BOTH,expand=TRUE)

root.mainloop()


#--------------------------------进度条 Progressbar-------------------------
"""
Progressbar():进度条,是tkinter.ttk模块,常用参数:
1.length:进度条的长度,默认为100像素
2.mode:可以有下列两种模式:
				(1)determinate:默认模式,一个指针从起点到终点。
				(2)indeterminate:一个指针在起点和重点来回移动。
3.maximum:进度条的最大值,默认是100
4.name:进度条名称,供程序参考引用
5.orient:进度条的方向,可以是HORIZONTAL(默认),或VERTICAL
5.value:进度条当前值
6.variable:记录进度条目前的进度值

Progressbar的方法:
value用update()方法更新值,以达到动画效果
1.start(interval):每隔interval时间移动一次指针,默认值是50ms
2.step(delta):在step()方法内的delta参数的意义是增量值,每次增加一次delta,默认值是1
3.stop:停止start()的运行
"""
from tkinter.ttk import *
import time

def run():
  pb.start()
def stop():
  pb.stop()

#	这个函数的作用每隔0.05秒进度条增加2,并打印当前值,满后重新开始。
def running():
	while pb.cget("value")<= pb["maximum"]:	#	当前值小于最大值时不断循环
		pb.step(2)	# 递增值为2
		root.update()		# 更新当前值(就是增加2后)
		print(pb.cget("value"))	#	打印出当前值
		time.sleep(0.05)	#	每隔0.05秒循环一次 


root = Tk()
root.title("进度条 Progressbar")
#	设置进度条长度、模式和方向
pb = Progressbar(root,length=200,mode="determinate",orient=HORIZONTAL)
pb.pack(padx=5,pady=10)
pb["maximum"] = 100	#	设置进度条最大值
pb["value"] = 0		#	设置进度条当前值(初始)

btnRun = Button(root,text="Run",command=run)	#	可以替换为running试试
btnRun.pack(side=LEFT,padx=5,pady=10)

btnStop = Button(root,text="Stop",command=stop)
btnStop.pack(side=LEFT,padx=5,pady=10)

root.mainloop()



#	-----------------------------------菜单栏 Menus------------------------
"""
Menu():下拉式菜单栏,常用参数:
tearoff:菜单上的虚线分隔线,当默认值为True或1时,菜单列表位置从1开始放置,同时点击虚线
				 可以让菜单分离出来单独的窗口,如果tearoff值为Fslse或0时,菜单列表由0开始,并且
				 此时不会显示虚线分隔线,菜单也无法分离出去。

相关方法:
add_cascade():建立分层菜单,同时让此子功能列表与父菜单建立连接。
add_command():增加菜单列表
add_separator():增加菜单列表分隔线(实线,子菜单列表过多时可用;方法直接作用在Menu上)

建立菜单列表时所用到的概念如下:
menubar = Menu(root)				#	建立最上层菜单
filemenu = menu(menbar)			#	在上层菜单的基础上建立菜单对象
menubar.add_cascade(label="File",menu=filemenu)		#	在最上层菜单上添加分层菜单,并链接

建立子菜单:
findmenu = Menu(filemenu)
filemenu.add_cascade(label="Find",menu=findmenu)	#	在分层菜单的基础上建立子菜单,并连接

ALT快捷键:就是某个菜单类别或列表指令的英文字符串内单一字母添加下划线,然后可以用ALT键先启动
					此功能。设计方法是在下列两个方法内增加underline参数
					1.add_cascade(....,underline=n)
					2.add_command(....,underline=n)		#	n代表第几个索引字母含下划线

要实现右击出现菜单可以在menu上绑定右击事件,然后在menu上使用.poss()方法调出菜单栏。P213

XXlabel.pack_forget()调用此方法可以隐藏次控件(可以用作事件处理函数)

在设计菜单列表是可以用add_checkbutton()创建复选框。

"""
#	import 不重复了
#	创建子菜单列表事件
def findNext():
	messagebox.showinfo("Find Next","查找下一个")
def findPre():
	messagebox.showinfo("Find Pre","查找下一个")
#创建分层菜单列表事件
def newFile():
  messagebox.showinfo("New File","新建文档")
def openFile():
  messagebox.showinfo("Open File","打开文档")
def saveFile():
  messagebox.showinfo("Save File","保存文档")
def saveAsFile():
  messagebox.showinfo("Save As File","另存为")
def aboutMe():
  messagebox.showinfo("About Me","XXXX")
#	创建右键菜单列表事件
def minmizeIcon():
  root.iconify()        # iconify方法的作用是缩小窗口为图标
def showPopupMenu(event):
  popupmenu.post(event.x_root,event.y_root) # 在鼠标的点击的位置x,y处弹出菜单
#	创建菜单栏中的复选框事件
def status():
	if demoStatus.get():	#	获取复选框是否被选上
		statusLabel.pack(side=BOTTOM,fill=X)	#	包装显示该控件
	else:
		statusLabel.pack_forget()	#.pack_forget()隐藏此控件

#	窗口设计
root = Tk()
root.title("菜单_Menu")
root.geometry("300x180")

menubar = Menu(root)
filemenu = Menu(menubar,tearoff=False) # 将分层菜单建立在上层菜单上,不显示虚线分隔线
menubar.add_cascade(label="File",menu=filemenu,underline=0) # 在第0个字母加下划线

#	创建分层菜单下的子菜单
findmenu = Menu(filemenu,tearoff=False)
findmenu.add_command(label="Find Next",command=findNext)	# 添加子菜单列表
findmenu.add_command(label="Find Pre",command=findPre)
filemenu.add_cascade(label="Find",menu=findmenu)

filemenu.add_command(label="New File",command=newFile,underline=0)	#添加菜单列表
filemenu.add_command(label="Open File",command=openFile,underline=0)
filemenu.add_separator()    # 创建实线分割线
filemenu.add_command(label="Save File",command=saveFile,underline=0)
filemenu.add_command(label="Save As File",command=saveAsFile,underline=5)
filemenu.add_separator()
filemenu.add_command(label="Exit",command=root.destroy,underline=0)

helpmenu = Menu(menubar)	#	这里保留虚线分隔线
menubar.add_cascade(label="Help",menu=helpmenu,underline=0) # underline拥有ALT快捷键

helpmenu.add_command(label="About Me",command=aboutMe,underline=0)


# 设计鼠标右击弹出菜单
popupmenu = Menu(root,tearoff=False)
popupmenu.add_command(label="Minimize",command=minmizeIcon) #	添加右击菜单列表
popupmenu.add_command(label="Exit",command=root.destroy)
root.bind("<Button-3>",showPopupMenu)   # 绑定右击事件

#	设计菜单栏中的复选框
viewmenu = Menu(menubar,tearoff=False)
menubar.add_cascade(label="View",menu=viewmenu)

demoStatus = BooleanVar()
demoStatus.set(True)	
viewmenu.add_checkbutton(label="Status",command=status,variable=demoStatus)
#	复选框中决定显示与隐藏的Label:
statusVar = StringVar()
statusVar.set("显示")
statusLabel = Label(root,textvariable=statusVar,relief="raised")
statusLabel.pack(side=BOTTOM,fill=X)

root.config(menu=menubar)		#	显示菜单栏对象,!!!不能漏了
root.mainloop()


#----------------------------------文字区域 Text-------------------------------
"""
Text(): 是一个文字区域控件,可以处理多行输入或镶嵌图像等编辑功能(相当于一个文本),常用参数:

1.exportselection:如果执行选择操作时,所选字符串会自动输出至剪切板,想避免设置值为0.
2.height/width:文字区域中的高度和宽度,单位是字符高和字符宽
3.padx/pady:text左右上下框与与文字各个方向的间距
4.relief:默认是relief=SUNKEN,文字外框样式。
5.state:输入状态:NORMAL / DISABLED
6.wrap:可以控制某行文字太长时的处理,默认是wrap=CHAR(??)
7.xscrollcommand:在x轴使用滚动条
8.yscrollcommand:在y轴使用滚动条(使用方法,yscrollcommand=滚动条对象)

字形FONT()方法:这里只填常用的3个参数 family字形,weight是否粗体,size大小
f=Font(family=xx,weight=nomal,size=xx);text.configure(font=f)
属于tkinter.font模块需要from tkinter.font import Font

Text的方法:
insert(index,string): 将文字插入指定的索引位置,另外第三个参数可以将插入文字添加为标签tag
get(startindex,endindex):获取text内容:get(SEL_FIRST,SEL_LAST)可以获取当前Text被选取的值
												get(1.0,END):获取全部值
text.delete(startindex,endindex):删除指定索引字段

Text的索引:(行.列:1.2表示1行第2列)
text.index(INSERT):目前插入点的位置(即光标所在坐标或索引)
text.index(CURRENT):和上面意思差不多,表示广播目前相对于字符串的位置
text.index(END):最后一个字符串的位置
text.index(SEL_FIRST):被选取文字的开始索引,SEL_LAST为结束索引

添加滚动条:
需要在创建Text和Scrobar都需要互相指定:(1)yscrollbar.config(command=text.yview)
																		 (2)text.config.(yscrollocommadn=yscrollbar.set)				
另外在tkinter.scrolledtext模块内有ScrolledT	ext控件可以创建默认含有滚动条的控件:
																	(1)from tkinter.scrolledtext import ScrolledText
																	(2)text = ScrolledText(root,undo=true)

建立书签(Marks)和标签(tag):
在文件特殊的位置建立书签,而标签tag是值一个区域文字
mark_names():传回这个Text对象的所有书签
index(mark):传回指定书签的line和column(索引)
mark_set(mark,index):在指定的index位置设置书签
mark_unset(mark):取消指定书签设置

tag_add(tagname,startindex[,endindex]...):将startindex到endindex之间的文字命名为tagname的标签
tag_config(tagname,options,..):编辑绑定标签,一般label参数差不多,wrap可使用模式NONE,CHAR,WORD
tag_delete(tagname):删除此标签,同时移除此标签特殊的编辑或绑定
tag_remove(tagname,startindex[,endindex]...):删除标签,但不删除标签定义和标签特殊的编辑或绑定

text.tag_config(SEL,options):除了tag_add()自定义标签外,系统还有一个内建的SEL,表示所选取的区间
		也可以在insert()的第三个参数增加标签"a",然后再text.tag_config("a",options)
通过书签创建标签:
text.mark_set("mark1",5.0)
text.mark_set("mark1",8.0)
text.tag_add("tag1,"mark1","mark1")
text.tag_config("tag1",foreground="blue",background="lightyellow")


Cut/Copy/Paste 功能:上述三个功能已经内奸为tkinter的虚拟事件可以直接引用:
text.event_geberate("<<Cut>>") text.event_geberate("<<Copy>>") text.event_geberate("<<Paset>>")

复原undo和重做redo:Text默认没有开启,开始需要在Text方法内增加undo=True:
									 Text.edit_undo() (复原,相当于返回上一步)
									 Text.edit_redo()	(恢复最原始状态)

查找文字 search()方法: pos = text.search(key,startindex,endindex) pos传回找到的字符串的索引位置
											key表示需要查找的字符串,startindex和endindex表示查找的起始和终止区域

调出文档保存和打开文档窗口: tkinter.filedialog中的模块asksaveasfilename和askopenfilename
filename = asksaveasfilename():启动另存为对话框,保存后传回文档的路径,输入参数
															asksaveasfilename(defaultextension=".text")设置默认后缀
filename = askopenfilename():启动打开文件对话框,打开后传回文档的路径

text.focus_set表示这个text对象获取焦点

"""
from tkinter.font import Font
from tkinter.ttk import *

def sizeSelected(event):
  f=Font(size=sizeVar.get())
  text.tag_config(SEL,font=f) # SEL系统内建标签,表示所选区域

# 右击菜单运行程序
def cutJob():
  text.event_generate("<<Cut>>")
def copyJob():
  text.event_generate("<<Copy>>")
def pasteJob():
  text.event_generate("<<Paste>>")
def showPopupMenu(event):
  popupmenu.post(event.x_root,event.y_root)

root = Tk()
root.title("TEXT文字区域")
root.geometry("300x180")

# 建立右击菜单
popupmenu = Menu(root,tearoff=False)
popupmenu.add_command(label="Cut",command=cutJob)
popupmenu.add_command(label="Copy",command=copyJob)
popupmenu.add_command(label="Paste",command=pasteJob)
root.bind("<Button-3>",showPopupMenu)

# 建立工具栏
toolbar = Frame(root,relief=RAISED,borderwidth=1)
toolbar.pack(side=TOP,fill=X,padx=2,pady=1)

# 建立font size combobox
sizeVar = IntVar()
size = Combobox(toolbar,textvariable=sizeVar)
sizeFamily = [x for x in range(8,30)] # 字体大小
size["value"] = sizeFamily
size.current(4)       # 默认选取索引4,就是12
size.bind("<<ComboboxSelected>>",sizeSelected)
size.pack()

# 建立TEXT
text = Text(root)
text.pack(fill=BOTH,expand=True,padx=3,pady=2)
text.insert(END,"Five Hundred Miles\n","aaa")	#	输入第3参数,将该段作为标签(此处无意义)
text.insert(END,"If you miss the rain I'm on\n")
text.insert(END,"You will know that I am gone.\n")
text.insert(END,"You can hear the whistle blow\n")
text.insert(END,"A hundred miles,\n")
text.focus_set()    # focus_set表示这个对象获取焦点

root.mainloop()


#	程序:查找文字

def mySearch():
	text.tag_remove("found","1.0",END) 	# 每一次查询前清除前一次标签(删除标签但不删除标签定义)
	start = "1.0"												# 设置起始位置
	key = entry.get()										#	读取查找关键词
	if (len(key.strip()) == 0):
		return
	while True:
		pos = text.search(key,start,END)
		if (pos == ""):
			break
		text.tag_add("found",pos,"%s+%dc" % (pos,len(key)))
		start = "%s+%dc" % (pos,len(key))		#	更新查找起始位置,从新的起始位置接着再查找

root = Tk()
root.title("查找文字")
root.geometry("300x180")
root.rowconfigure(1,weight=1)
root.columnconfigure(0,weight=1) 	#	拉伸缩放比例

entry = Entry()
entry.grid(row=0,column=0,padx=5,sticky=W+E)

btn = Button(root,text="查找",command=mySearch)
btn.grid(row=0,column=1,padx=5,pady=5)

text = Text(root,undo=True)
text.grid(row=1,column=0,columnspan=2,padx=3,pady=5,sticky=N+S+W+E)
text.insert(END,"Five Hundred Miles\n")	
text.insert(END,"If you miss the rain I'm on\n")
text.insert(END,"You will know that I am gone.\n")
text.insert(END,"You can hear the whistle blow\n")
text.insert(END,"A hundred miles,\n")

text.tag_config("found",background="yellow")	#	定义找到的标签
root.mainloop()


#	程序打开保存文档
from tkinter.filedialog  import asksaveasfilename
from tkinter.filedialog  import askopenfilename

# 设计菜单栏3个功能函数
def newFile():
	text.delete("1.0",END)	#	删除Text控件内容
	root.title("Untitled")	#	新建文件交后修改窗口名

def openFile():
	global filename
	filename = askopenfilename()	#	掉出打开文件窗口,读取打开的文档名地址
	if filename == "":
		return
	with open(filename,"r") as fileObj:
		content = fileObj.read()
	text.delete("1.0",END)
	text.insert(END,content)
	root.title(filename)

def saveAsFile():
	global filename
	textContent = text.get("1.0",END)
	filename = asksaveasfilename(defaultextension=".txt") #	开启另存为对话框
	if filename == "":
		return
	with open(filename,"w") as output:
		output.write(textContent)
		root.title(filename)

filename="Untitled"
root = Tk()
root.title(filename)
root.geometry("300x180")

menubar = Menu(root)
filemenu = Menu(menubar,tearoff=False)
menubar.add_cascade(label="File",menu=filemenu)

filemenu.add_command(label="New File",command=newFile)
filemenu.add_command(label="Open File",command=openFile)
filemenu.add_command(label="Save AS File",command=saveAsFile)
filemenu.add_separator()
filemenu.add_command(label="Exit",command=root.destroy)
root.config(menu=menubar)	#	显示菜单对象

text = Text(root,undo=True)
text.pack(fill=BOTH,expand=True)
root.mainloop()


#--------------------------------Treeview 树状表格数据------------------------------
"""
Treeview():一种表格视图结构的控件,控件最左列为图标栏,右侧为一般栏,是tkinter.tkk的控件;参数:

1.columns:栏位的字符串,其中第一个为图标栏是默认的,不需要设置;赋予的值为一般栏
2.displaycolumns:设置栏位显示顺序。
3.height:控件每行高度
4.padding:设置内容与控件框的间距,规则P254
5.sekectmode:用户可以使用鼠标选择项目的方式:
							1.selectmode=BROWSE,一次选择一项,这是默认的
							2.selectmode=EXTENDED,一次可以选择多项
							3.selectmode=NONE,无法用鼠标执行选择
6.show:默认是设置显示图标栏标签show="tree",如果省略隐藏图标栏则设置show="heading"

tree_obj.heading(#x,text="xxxx"):用来建立栏标题,其中x为栏标题的col数或栏位字符串,xxxx为栏标题的名称
								一般用Treeview()创建栏位和控件,再用heaing()创建栏标题,最后用insert()插入栏内容。
insert("",index=END,text="aaa",values="bbb"):按顺序插入数据,其中第一个参数""为父id,层级式Treeview
					时用来绑定父id,text为图标栏内容,values为一般栏内容,按从左到右的顺序(values可以用元组列表)

column(id,options):用于格式化Treeview栏位,id为#index的索引或栏位字符串,options参数:
									1.anchor:可以设置栏内容参考位置,CENTER为居中
									2.minwidth:最小栏宽,默认为20像素
									3.stretch:默认是1,当控件大小改变时,栏宽随着改变的幅度
									4.width:默认栏宽是200像素
									可以使用:ret = column(id)不含参数,将会以字典的方式传回特定栏所有参数内容

tag_configure("tagName",option):此方法可以建立标签,然后定义此标签的格式:
																1.background:标签背景颜色
																2.font:字形设置
																3.forground:标签前景颜色
																4.image:图像与列表同时显示。
		创建标签后,需要在插入数据时,将插入行绑定已经创建的标签:insert(····,tags="tagName")

层级Treeview:1.要在图标栏先建立top_level的项目id:idxx=tree.insert("",index=END,text="XXX")
							2.再将相关子项目放在所属的top_level项目id:tree.insert("idxx",index=END,·······)

Style().configure("Treeview",rowheight=xx):添加图像时增加row高度

selection选项事件:鼠标选择时会触发虚拟事件<<TreeviewSelect>>,然后通过对Treeview控件使用
  								selection()方法获取其目前所选项目iid(iid是tiknter内部使用的id),获取类型为元组

delete(id):作用在Treeview控件内,删除对应的项目,参数为所删除项目的id(selection方法选取后需要遍历)

identify("xxx",event.x,event.y):"xxx"可以是item、column、row,使用双击时获取坐标和item、column或row信息,
"""
from tkinter.ttk import *

root = Tk()
root.title("层级Treeview")

asia = {"中国":"北京","日本":"东京","泰国":"曼谷","韩国":"首尔"}
euro = {"英国":"伦敦","法国":"巴黎","德国":"柏林","挪威":"奥斯陆"}

# 建立Treeview,选择模式为多选
tree = Treeview(root,columns=("capital"),selectmode=EXTENDED)

# 建立栏标题
tree.heading("#0",text="国家")
tree.heading("capital",text="首都")

# 建立top—level项目id
idAsia = tree.insert("",index=END,text="Asia")
idEuro = tree.insert("",index=END,text="Europe")

# 建立idAsia和idEuro底下内容
for country in asia.keys():
  tree.insert(idAsia,index=END,text=country,values=asia[country])
for country in euro.keys():
  tree.insert(idEuro,index=END,text=country,values=euro[country])

tree.column("capital",anchor=CENTER)
tree.pack(fill=BOTH,expand=True)  # 拉伸时填满

root.mainloop()

#	-----------------------------------------------------------------------

#	案例2:
from tkinter.ttk import *
from tkinter import messagebox

def removeItem():           # 删除所选的项目
  ids = tree.selection()    # 获取所选的项目
  for id in ids:
    tree.delete(id)

def insertItem():                 # 插入项目  
  state = stateEntry.get()        # 获取Entry输入的内容
  city = cityEntry.get()
  if (len(state.strip()) == 0 or len(city.strip()) == 0 ):  #如果为空则跳过
    return
  tree.insert("",END,text=state,values=(city))  # 插入
  stateEntry.delete(0,END)  # 清空Entry
  cityEntry.delete(0,END)

# 创建双击事件
def doubleClick(event):
  e = event.widget        # 获取触发事件控件,此处可以省略因,为已知是tree
  iid = e.identify("item",event.x,event.y)  # 获取双击项目id
  state = e.item(iid,"text")                # 取得state
  city = e.item(iid,"values")[0]            # 取得City
  str = "{0}:{1}".format(state,city)        # 格式化
  messagebox.showinfo("Double Clicked",str) # 输出

# 建立点击选取时,下方出现所选项
def treeSelect(event):
  itemselected = tree.selection()[0]           # 获取所选项
  col1 = tree.item(itemselected,"text")        # 取得图标栏内容 
  col2 = tree.item(itemselected,"values")[0]   # 取得第0索引栏位内容
  str = "{0}:{1}".format(col1,col2) 
  var.set(str)                                 #  设置状态栏内容

# 建立排序函数(不怎么懂)
reverseFlag = False 						#	排序标识著名是否反向排序
def treeview_sortColumn(col):
  global reverseFlag						#	定义排序表示为全局变量
#get_children([item])方法传回item的一个tuple的iid值,如果省略则得到一个tuple
  lst = [(tree.set(st,col),st) for st in tree.get_children("")]
#  print(lst)
  lst.sort(reverse=reverseFlag)	#	排序
#  print(lst)
  for index,item in enumerate(lst):
#	move(iid,parent,index):将iid所指项目移至parent层次的index位置这里""表示panrent层次
    tree.move(item[1],"",index)	
  reverseFlag = not reverseFlag

root = Tk()
root.title("Treeview案例2")

stateCity = {"伊利若":"芝加哥","加州":"洛杉矶","德州":"休斯敦","华盛顿州":"西雅图",
             "江苏":"南京","山东":"青岛","广东":"广州","福建":"厦门","Mississippi":"Oxford",
             "Kentucky":"Lexington","Florida":"Miama","Indiana":"West Lafeyette"}

# 设置窗口拉伸时缩放
root.rowconfigure(1,weight=1)
root.columnconfigure(1,weight=1)
root.columnconfigure(3,weight=1)

# 建立上层插入项目
stateLeb = Label(root,text="State:")
stateLeb.grid(row=0,column=0,padx=5,pady=3,sticky=W)
stateEntry = Entry()
stateEntry.grid(row=0,column=1,sticky=W+E,padx=5,pady=3)
cityLab = Label(root,text="City:")
cityLab.grid(row=0,column=3,sticky=E)
cityEntry = Entry()
cityEntry.grid(row=0,column=3,sticky=W+E,padx=5,pady=3)

# 建立Insert按钮
InBtn = Button(root,text="插入",command=insertItem)
InBtn.grid(row=0,column=4,padx=5,pady=3)

#建立Treeview
tree = Treeview(root,columns=("cities"),selectmode=EXTENDED)	#	设置多选模式
tree.heading("#0",text="State")
tree.heading("cities",text="City")
tree.column("cities",anchor=CENTER)
tree.tag_configure("evenColor",background="lightblue")  # 创建标签,颜色为浅蓝色
# 插入内容,双数行设置为标签(根据标签定义,颜色为浅蓝色)
rowCount = 1
for state in stateCity.keys():
  if (rowCount % 2 == 1):
    tree.insert("",index=END,text=state,values=stateCity[state])
  else:
    tree.insert("",index=END,text=state,values=stateCity[state],tags=("evenColor"))
  rowCount += 1

tree.grid(row=1,column=0,columnspan=5,padx=3,sticky=W+E+N+S)
tree.bind("<Double-1>",doubleClick)         # 绑定双击事件运行函数
tree.bind("<<TreeviewSelect>>",treeSelect)  # 绑定选择虚拟事件运行函数

rmBtn = Button(root,text="删除",command=removeItem)
rmBtn.grid(row=2,column=2,padx=5,pady=3,sticky=W)

# 创建最底层的状态栏显示
var = StringVar()
label = Label(root,textvariable=var)
label.grid(row=3,column=0,sticky=W,columnspan=5) 

# 创建滚动条
yscrollbar = Scrollbar(root)
yscrollbar.config(command=tree.yview)         # 连接tree控件
tree.configure(yscrollcommand=yscrollbar.set) # tree控件绑定滚动条
yscrollbar.grid(row=1,column=5,sticky=N+S+W,padx=0) # 设置滚动条位置

# 单击标调栏将启动treeview_sortColumn函数排序(text为栏标题名,c为栏位名)
tree.heading("#1",text="City",command=lambda c="cities":treeview_sortColumn(c))
# 关于标题栏无法排序问题暂时不知道怎么解决,主要不知道标题栏c=""的名称是什么
# tree.heading("#0",text="state",command=lambda c="???":treeview_sortColumn(c))

root.mainloop()