introduction
Similar to the drop-down box (combo box) combobox of TinUI, the list box also displays a number of selectable text segments to the user, calling the response function after the user clicks the selection, and passing the selected parameters, that is, the selected text segment text. So are these two components contradictory? Of course not.
Application scenario of combobox:
-
Number of finite elements
-
Short text length
To sum up, it is small and fine. The application scenario of listbox:
-
Many options
-
The length and format of the optional text vary greatly, generally long text or complex format text
-
Occupied position fixed
Therefore, the two components are actually complementary. In addition, TinUI has completed the drawing of the scroll bar, which lays a foundation for the creation of these components with variable field of view.
layout
Function structure
def add_listbox(self,pos:tuple,width:int=200,height:int=200,font='Microsoft YaHei 12',data=('a','b','c'),bg='#f2f2f2',fg='black',activebg='#e9e9e9',sel='#b4bbea',anchor='nw',command=None):#Draw list box ''' pos::Starting position width::width height::height font::typeface data::Unary element set, optional prompt text data bg::Background color fg::Text and scroll bar colors activebg::The background color of the response mouse sel::Background color when selected anchor::align orientation command::The callback function must accept a parameter, the selected text '''
Component framework
Because we need to use the scroll bar, we use two basic tin UI components nested.
frame=BasicTinUI(self,bg=bg)#Main display box, displaying scroll bar box=BasicTinUI(frame,bg=bg,width=width,height=height)#Show selection box.place(x=12,y=12)
Bind scroll bar
It's just like using tkinter native scroll bar, but it's easier. You only need to bind it once. This is also equivalent to an official example of TinUI scroll bar binding "extra components".
uid=self.create_window(pos,window=frame,width=width+24,height=height+24,anchor=anchor) frame.add_scrollbar((width+12,12),widget=box,height=height,bg=bg,color=fg,oncolor=fg)#portrait frame.add_scrollbar((12,height+12),widget=box,height=height,direction='x',bg=bg,color=fg,oncolor=fg)#transverse
Logic different from combobox
You can think of it as an improvement of my logic level. In listbox, we will use independent data structure to judge the different response of each option to the event.
This variable is as follows:
choices={}#'a':[a_text,a_back,is_sel:bool]
That is, take the text content as the key to correspond to the values of text object, background box object and selected status respectively.
Add optional elements
Redrawing techniques similar to combobox and table will not be repeated here. Please see those two articles for details.
maxwidth=0#Maximum width for i in data: end=box.bbox('all') end=5 if end==None else end[-1] text=box.create_text((5,end+7),text=i,fill=fg,font=font,anchor='nw') bbox=box.bbox(text) twidth=bbox[2]-bbox[0] maxwidth=twidth if twidth>maxwidth else maxwidth back=box.create_rectangle((3,bbox[1]-2,bbox[2]+2,bbox[3]+2),width=0,fill=bg) box.tkraise(text) choices[i]=[text,back,False] box.tag_bind(text,'<Enter>',lambda event,text=i : in_mouse(text)) box.tag_bind(text,'<Leave>',lambda event,text=i : out_mouse(text)) box.tag_bind(text,'<Button-1>',lambda event,text=i : sel_it(text)) box.tag_bind(back,'<Enter>',lambda event,text=i : in_mouse(text)) box.tag_bind(back,'<Leave>',lambda event,text=i : out_mouse(text)) box.tag_bind(back,'<Button-1>',lambda event,text=i : sel_it(text)) if maxwidth<width:#Judge the maximum width maxwidth=width repaint_back()#Repaint
The redrawing function is as follows:
def repaint_back(): for v in choices.values(): bbox=box.coords(v[1]) box.coords(v[1],3,bbox[1]-2,5+maxwidth+2,bbox[3]+2)
Don't forget to bind the visual range.
bbox=box.bbox('all') box.config(scrollregion=bbox) def set_y_view(event): box.yview_scroll(int(-1*(event.delta/120)), "units") box.bind('<MouseWheel>',set_y_view)
Binding style
Because the above has bound the event response of each canvas object to the mouse, the bound function is directly indicated here.
Mouse in and out events:
def in_mouse(t): if choices[t][2]==True:#Selected return box.itemconfig(choices[t][1],fill=activebg) def out_mouse(t): if choices[t][2]==True:#Selected box.itemconfig(choices[t][1],fill=sel) else: box.itemconfig(choices[t][1],fill=bg)
As you can see, we judge whether this option has been selected through the data structure. If not, we will adjust the style, otherwise we will not do any processing.
Using this method, you can avoid the tedious process of determining the style change operation through the style judgment of the canvas object.
Select action:
def sel_it(t): box.itemconfig(choices[t][1],fill=sel) choices[t][2]=True for i in choices.keys(): if i==t: continue choices[i][2]=False out_mouse(i) if command!=None: command(t)
In addition to the judgment of variable data structure, other logic and operations such as selection, deselection and style recovery are the same as combobox.
Complete code function
def add_listbox(self,pos:tuple,width:int=200,height:int=200,font='Microsoft YaHei 12',data=('a','b','c'),bg='#f2f2f2',fg='black',activebg='#e9e9e9',sel='#b4bbea',anchor='nw',command=None):#Draw list box def repaint_back(): for v in choices.values(): bbox=box.coords(v[1]) box.coords(v[1],3,bbox[1]-2,5+maxwidth+2,bbox[3]+2) def in_mouse(t): if choices[t][2]==True:#Selected return box.itemconfig(choices[t][1],fill=activebg) def out_mouse(t): if choices[t][2]==True:#Selected box.itemconfig(choices[t][1],fill=sel) else: box.itemconfig(choices[t][1],fill=bg) def sel_it(t): box.itemconfig(choices[t][1],fill=sel) choices[t][2]=True for i in choices.keys(): if i==t: continue choices[i][2]=False out_mouse(i) if command!=None: command(t) frame=BasicTinUI(self,bg=bg)#Main display box, displaying scroll bar box=BasicTinUI(frame,bg=bg,width=width,height=height)#Show selection box.place(x=12,y=12) uid=self.create_window(pos,window=frame,width=width+24,height=height+24,anchor=anchor) frame.add_scrollbar((width+12,12),widget=box,height=height,bg=bg,color=fg,oncolor=fg)#portrait frame.add_scrollbar((12,height+12),widget=box,height=height,direction='x',bg=bg,color=fg,oncolor=fg)#transverse choices={}#'a':[a_text,a_back,is_sel:bool] maxwidth=0#Maximum width for i in data: end=box.bbox('all') end=5 if end==None else end[-1] text=box.create_text((5,end+7),text=i,fill=fg,font=font,anchor='nw') bbox=box.bbox(text) twidth=bbox[2]-bbox[0] maxwidth=twidth if twidth>maxwidth else maxwidth back=box.create_rectangle((3,bbox[1]-2,bbox[2]+2,bbox[3]+2),width=0,fill=bg) box.tkraise(text) choices[i]=[text,back,False] box.tag_bind(text,'<Enter>',lambda event,text=i : in_mouse(text)) box.tag_bind(text,'<Leave>',lambda event,text=i : out_mouse(text)) box.tag_bind(text,'<Button-1>',lambda event,text=i : sel_it(text)) box.tag_bind(back,'<Enter>',lambda event,text=i : in_mouse(text)) box.tag_bind(back,'<Leave>',lambda event,text=i : out_mouse(text)) box.tag_bind(back,'<Button-1>',lambda event,text=i : sel_it(text)) if maxwidth<width: maxwidth=width repaint_back() bbox=box.bbox('all') box.config(scrollregion=bbox) def set_y_view(event): box.yview_scroll(int(-1*(event.delta/120)), "units") box.bind('<MouseWheel>',set_y_view) return box,uid
effect
Test code
def test(event): a.title('TinUI Test') b.add_paragraph((50,150),'This is TinUI The event function reached by the button is echoed. In addition, the window title is also changed and the indent of the first line title is reduced') b.coords(m,100,5) def test1(word): print(word) def test2(event): ok1() def test3(event): ok2() def test4(event): from time import sleep for i in range(1,101): sleep(0.02) progressgoto(i) def test5(result): b.itemconfig(scale_text,text='Current selected value:'+str(result)) if __name__=='__main__': a=Tk() a.geometry('700x700+5+5') b=TinUI(a,bg='white') b.pack(fill='both',expand=True) m=b.add_title((600,0),'TinUI is a modern way to show tkinter widget in your application') m1=b.add_title((0,680),'test TinUI scrolled',size=2,angle=24) b.add_paragraph((20,290),''' TinUI Is based on tkinter Canvas development interface UI Layout scheme as tkinter Expand and TinEngine Exist with the expansion of. At present, TinUI Available for project.''', angle=-18) b.add_paragraph((20,100),'The following paragraph is to test the non parallel font display effect of the canvas TinUI Brief introduction of') b.add_button((250,450),'Test button',activefg='white',activebg='red',command=test,anchor='center') b.add_checkbutton((80,430),'allow TinUI test',command=test1) b.add_label((10,220),'This is made of canvas TinUI Drawn Label assembly') b.add_entry((250,330),350,'This is used for input',command=print) b.add_separate((20,200),600) b.add_radiobutton((50,480),300,'sky is blue, water is blue, too. So, what is your heart',('red','blue','black'),command=test1) b.add_link((400,500),'TinGroup knowledge base','http://tinhome.baklib-free.com/') b.add_link((400,530),'implement print function',print) _,ok1,_=b.add_waitbar1((500,220),bg='#CCCCCC') b.add_button((500,270),'Stop waiting for animation',activefg='cyan',activebg='black',command=test2) bu1=b.add_button((700,200),'Stop dot scroll bar',activefg='white',activebg='black',command=test3)[1] bu2=b.add_button((700,250),'nothing button 2')[1] bu3=b.add_button((700,300),'nothing button 3')[1] b.add_labelframe((bu1,bu2,bu3),'box buttons') _,_,ok2,_=b.add_waitbar2((600,400)) b.add_combobox((600,550),text='How likely are you to go to Mount Everest',content=('20%','40%','60%','80%','100%','1000%')) b.add_button((600,480),text='Test progress bar (no event version)',command=test4) _,_,_,progressgoto,_,_=b.add_progressbar((600,510)) b.add_table((180,630),data=(('a','space fans over the\nworld','c'),('you\ncan','2','3'),('I','II','have a dream, then try your best to get it!'))) b.add_paragraph((300,850),text='Above is a table') b.add_onoff((600,100)) b.add_spinbox((680,100)) b.add_scalebar((680,50),command=test5) scale_text,_=b.add_label((890,50),text='Current selected value: 2') b.add_info((680,140),info_text='this is info widget in TinUI') mtb=b.add_paragraph((0,720),'Test menu (right click)') b.add_menubar(mtb,cont=(('command',print),('menu',test1),'-',('TinUI Text movement',test))) ttb=b.add_paragraph((0,800),'TinUI What can you do?') b.add_tooltip(ttb,'numerous') b.add_back(pos=(0,0),uids=(ttb,),bg='cyan') _,_,ok3,_=b.add_waitbar3((600,800),width=240) b.add_button((600,750),text='Stop ribbon wait box',command=lambda event:ok3()) textbox=b.add_textbox((890,100),text='This is a text input box. Of course, it can't be in textbox Bind horizontal scrolling in parameters of'+'\n Line feed'*30)[0] textbox['wrap']='none' b.add_scrollbar((1095,100),textbox) b.add_scrollbar((890,305),textbox,direction='x') b.add_listbox((890,430),data=('item1','item2','item3','item4\n item4.1\n item4.2\n item4.3\n itme4.4\n item4.5','item5 and item5.1 and item5.2 and item5.3'), command=print) a.mainloop()
Final effect
github project
github project address of TinUI
pip Download
pip install tinui
Modify open source agreement
From February 2022, TinUI (including TinUIXml Technology) uses GPLv3 open source protocol. To use TinUI in your software or program, please follow the TinUI open source agreement and open source terms.
For open source terms, see github project address of TinUI.
epilogue
TinUI has launched the latest modern xml layout method - TinUIXml. Use it quickly!!!
May the world be peaceful and the motherland be strong and prosperous
🔆 tkinter innovation 🔆