Python GUI设计 tkinter 笔记

#  《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时间本触发时,运行相关的程序或函数。
列取相关鼠标事件:
:单击鼠标左键,鼠标光标相对空间位置会被存入时间对象的x和y变量。
:单击鼠标中键,鼠标光标。。。。。。。
:单击鼠标右键,。。。。。。。。
:鼠标滑轮向上滚动,。。。。。。。
:鼠标滑轮向下滚动,。。。。。。。
:鼠标移动,。。。。。。
:拖拽,按住鼠标左键再移动,。。。。。。
:拖拽,按住鼠标中键再移动,。。。。。。
:拖拽,按住鼠标右键再移动,。。。。。。
:放开鼠标左键,。。。。。。
:放开鼠标中键,。。。。。。
:放开鼠标游右键,。。。。。。
:双击左键,。。。。。。
:双击中建,。。。。。。
:双击右键,。。。。。。
:鼠标进入wiget控件
:鼠标离开wiget控件

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

控件事件:
:更改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)			#鼠标进入EXIT区域自动触发Enter事件,从而触发处理程序entry()
btn.bind("",leave)
btn.bind("",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("")

# 窗口管理程序:触发事件"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选取操作会产生<>虚拟事件:

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("<>",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选项有变动时,会产生虚拟<>事件,也可以用这个特性绑定处理方法
"""
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("<>",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("",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("<>") text.event_geberate("<>") text.event_geberate("<>")

复原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("<>")
def copyJob():
  text.event_generate("<>")
def pasteJob():
  text.event_generate("<>")
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("",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("<>",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选项事件:鼠标选择时会触发虚拟事件<>,然后通过对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("",doubleClick)         # 绑定双击事件运行函数
tree.bind("<>",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()






 

你可能感兴趣的:(Python,GUI,tkinter)