这次是要求treeview的每一行对应一个多选按钮, 功能:1.勾选按钮,tree对应的行就会改变颜色 2.点击tree的行,按钮也相应的被打勾 3.全选按钮会根据 下面多选按钮的情况,改变状态! 代码要点:1.操作滚动条时,对应移动的是tree+按钮,所以得用canvas,还得设定!! 2.因为是tree整体滚动,所得还得另外设定一个头(label) PS:如果能把tree的heading去掉就更好了! 3.格式问题===得设定tree每一行的高度,跟button相同; 设定tree的字体,还有背景颜色 设定canvas的高度随tree高度而改变 4.按钮跟tree的行对应,匹配,设定回调函数 5.tree的每一项被选中时,就改变其颜色
from tkinter import *
from tkinter.ttk import *
class My_Tk():
def __init__(self):
self.tk=Tk()
self.tk.geometry('620x400')
self.orm={}
self.create_button()
self.create_heading()
self.create_tv()
mainloop()
def create_button(self):
Button(self.tk,text='增加数据',command=self.insert_tv).pack()
def create_heading(self,):
'''重新做一个treeview的头,不然滚动滚动条,看不到原先的头!!!'''
heading_frame=Frame(self.tk)
heading_frame.pack(fill=X)
#填充用
button_frame=Label(heading_frame,width=0.5)
button_frame.pack(side=LEFT,)
#全选按钮
self.all_buttonvar = IntVar()
self.all_button = Checkbutton(heading_frame, text='',variable=self.all_buttonvar, command=self.select_all)
self.all_button.pack(side=LEFT)
self.all_buttonvar.set(0)
self.columns = ['日期', '楼房', '房号', '房租', '发送详情']
self.widths = [100, 100, 100, 100, 100]
#重建tree的头
for i in range(len(self.columns)):
Label(heading_frame,text=self.columns[i],width=int(self.widths[i]*0.16),anchor='center',relief=GROOVE).pack(side=LEFT)
def create_tv(self):
#放置 canvas、滚动条的frame
canvas_frame=Frame(self.tk,width=600,height=400)
canvas_frame.pack(fill=X)
#只剩Canvas可以放置treeview和按钮,并且跟滚动条配合
self.canvas=Canvas(canvas_frame,width=500,height=500,scrollregion=(0,0,500,400))
self.canvas.pack(side=LEFT,fill=BOTH,expand=1)
#滚动条
ysb = Scrollbar(canvas_frame, orient=VERTICAL, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=ysb.set)
ysb.pack(side=RIGHT, fill=Y)
#!!!!=======重点:鼠标滚轮滚动时,改变的页面是canvas 而不是treeview
self.canvas.bind_all("",lambda event:self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units"))
#想要滚动条起效,得在canvas创建一个windows(frame)!!
tv_frame=Frame(self.canvas)
self.tv_frame=self.canvas.create_window(0, 0, window=tv_frame, anchor='nw',width=600,height=400)#anchor该窗口在左上方
#放置button的frame
self.button_frame=Frame(tv_frame)
self.button_frame.pack(side=LEFT, fill=Y)
Label(self.button_frame,width=3).pack() #填充用
#创建treeview
self.tv = Treeview(tv_frame, height=10, columns=self.columns, show='headings')#height好像设定不了行数,实际由插入的行数决定
self.tv.pack(expand=1, side=LEFT, fill=BOTH)
#设定每一列的属性
for i in range(len(self.columns)):
self.tv.column(self.columns[i], width=0, minwidth=self.widths[i], anchor='center', stretch=True)
#设定treeview格式
# import tkinter.font as tkFont
# ft = tkFont.Font(family='Fixdsys', size=20, weight=tkFont.BOLD)
self.tv.tag_configure('oddrow', font='Arial 12') #设定treeview里字体格式font=ft
self.tv.tag_configure('select', background='SkyBlue',font='Arial 12')#当对应的按钮被打勾,那么对于的行背景颜色改变!
self.rowheight=27 #很蛋疼,好像tkinter里只能用整数!
Style().configure('Treeview', rowheight=self.rowheight) #设定每一行的高度
# 设定选中的每一行字体颜色、背景颜色 (被选中时,没有变化)
Style().map("Treeview",
foreground=[ ('focus', 'black'), ],
background=[ ('active', 'white')]
)
self.tv.bind('<>', self.select_tree) #绑定tree选中时的回调函数
def insert_tv(self):
#清空tree、checkbutton
items = self.tv.get_children()
[self.tv.delete(item) for item in items]
self.tv.update()
for child in self.button_frame.winfo_children()[1:]: #第一个构件是label,所以忽略
child.destroy()
#重设tree、button对应关系
self.orm={}
for i in range(20):
tv_item=self.tv.insert('', i, value=[i,i,i,i,''],tags=('oddrow'))#item默认状态tags
import tkinter
ck_button = tkinter.Checkbutton(self.button_frame,variable=IntVar())
ck_button['command']=lambda item=tv_item:self.select_button(item)
ck_button.pack()
self.orm[tv_item]=[ck_button]
#每次点击插入tree,先设定全选按钮不打勾,接着打勾并且调用其函数
self.all_buttonvar.set(0)
self.all_button.invoke()
#更新canvas的高度
height = (len(self.tv.get_children()) + 1) * self.rowheight # treeview实际高度
self.canvas.itemconfigure(self.tv_frame, height=height) #设定窗口tv_frame的高度
self.tk.update()
self.canvas.config(scrollregion=self.canvas.bbox("all"))#滚动指定的范围
def select_all(self):
'''全选按钮的回调函数
作用:所有多选按钮打勾、tree所有行都改变底色(被选中)'''
for item,[button] in self.orm.items():
if self.all_buttonvar.get()==1:
button.select()
self.tv.item(item, tags='select')
else:
button.deselect()
self.tv.item(item, tags='oddrow')
def select_button(self,item):
'''多选按钮的回调函数
作用:1.根据按钮的状态,改变对应item的底色(被选中)
2.根据所有按钮被选的情况,修改all_button的状态'''
button=self.orm[item][0]
button_value=button.getvar(button['variable'])
if button_value=='1':
self.tv.item(item,tags='select')
else:
self.tv.item(item, tags='oddrow')
self.all_button_select()#根据所有按钮改变 全选按钮状态
def select_tree(self,event):
'''tree绑定的回调函数
作用:根据所点击的item改变 对应的按钮'''
select_item=self.tv.focus()
button = self.orm[select_item][0]
button.invoke() #改变对应按钮的状态,而且调用其函数
def all_button_select(self):
'''根据所有按钮改变 全选按钮状态
循环所有按钮,当有一个按钮没有被打勾时,全选按钮取消打勾'''
for [button] in self.orm.values():
button_value = button.getvar(button['variable'])
if button_value=='0':
self.all_buttonvar.set(0)
break
else:
self.all_buttonvar.set(1)