Tkinter布局助手代码模版语法
简介
为满足不同用户的需求,tkinter布局助手推出了自定义模版,用户可根据自己的需求生成代码。
tk文件
在开始学习模板语法前,需要先了解一下tk文件是什么,tk文件其实是一段json代码经过base64编码后的一段文本。详见源码。
以下是一个tk文件中的json信息,在顶层是窗口的坐标以及配置信息,“elements"键下是窗口内的组件相应信息,如果是容器类组件也包含"elements"键
|
|
模版语法
在模版中读取窗口的json信息
要使用模板的语法,必须用“{{}}”将语法包裹起来
{{it.text}} // 输出: Tkinter布局助手
{{it.is_ttkbootstrap}} // 输出: false
条件语句 if elif else
条件分支语句
{{ @if(it.is_ttkbootstrap == true) }}
from ttkbootstrap import *
{{ #else }}
from tkinter.ttk import *
{{ /if }}
遍历所有组件
将json中的树状数据转为列表数据,该语句会返回所有的组件信息和它的父级组件的信息。
{{ @widgets => parent,widget }}
{{ @if(parent.type == 'tk_win') }}
如果父组件类型是“tk_win”输出这段内容
{{ #elif(parent.type == 'tk_tabs') }}
如果父组件类型是“tk_tabs”输出这段内容
{{ #else }}
其他情况输出这段内容
{{ /if }}
{{ /widgets }}
遍历列表 each
以下示例遍历窗口的菜单生成相应代码。
def create_menu(self):
menu = Menu(self,tearoff=False)
{{ @each(it.menus) => menu }}
menu.add_command(label="{{menu.name}}",command=self.{{menu.call}})
{{ /each }}
遍历事件 event
遍历所有组件绑定的所有事件。示例中:为所有事件创建事件回调方法。
{{ @events=> ele }}
def {{ele.func}}(self,evt):
print("{{ele.evt | safe}}事件未处理:",evt)
{{ /events }}
bootstyle
返回 ttkbootstrap 的颜色和样式配置
btn = Button(parent, text="按钮", takefocus=False,{{ @bootstyle(widget) /}})
注释
{{! /* 这里是注释信息 不好被渲染 */}}
其他
{{ @if(it.menus.lenght == 0) }}
在表达式中 可以使用js语法
{{ /if}}
在语句中使用三元表达式
{{ it.frame == true ? '是容器' : '不是容器' }}
完整的模版示例
以下是tkinter布局助手默认的模板
"""
本代码由[Tkinter布局助手]生成
官网:https://www.pytk.net/tkinter-helper
QQ交流群:788392508
"""
from tkinter import *
from tkinter.ttk import *
from typing import Dict
{{ @if(it.is_ttkbootstrap) }}
from ttkbootstrap import *
from pytkUI.widgets import *
{{ /if }}
class WinGUI(Tk):
widget_dic: Dict[str, Widget] = {}
def __init__(self):
super().__init__()
self.__win()
{{ ! /* 处理组件创建和赋值 */ }}
{{ @widgets => parent,widget }}
{{ @if(parent.type == 'tk_win') }}
self.widget_dic["{{ widget.type }}_{{ widget.id }}"] = self.__{{ widget.type }}_{{ widget.id }}(self)
{{ #elif(parent.type == 'tk_tabs') }}
self.widget_dic["{{ widget.type }}_{{ widget.id }}"] = self.__{{ widget.type }}_{{ widget.id }}( self.widget_dic["{{ parent.type }}_{{ parent.id }}_{{ widget.tab }}"])
{{ #else }}
self.widget_dic["{{ widget.type }}_{{ widget.id }}"] = self.__{{ widget.type }}_{{ widget.id }}( self.widget_dic["{{ parent.type }}_{{ parent.id }}"])
{{ /if }}
{{ /widgets }}
def __win(self):
self.title("Tkinter布局助手")
# 设置窗口大小、居中
width = {{ it.width }}
height = {{ it.height }}
screenwidth = self.winfo_screenwidth()
screenheight = self.winfo_screenheight()
geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
self.geometry(geometry)
self.resizable(width=False, height=False)
# 自动隐藏滚动条
def scrollbar_autohide(self,bar,widget):
self.__scrollbar_hide(bar,widget)
widget.bind("<Enter>", lambda e: self.__scrollbar_show(bar,widget))
bar.bind("<Enter>", lambda e: self.__scrollbar_show(bar,widget))
widget.bind("<Leave>", lambda e: self.__scrollbar_hide(bar,widget))
bar.bind("<Leave>", lambda e: self.__scrollbar_hide(bar,widget))
def __scrollbar_show(self,bar,widget):
bar.lift(widget)
def __scrollbar_hide(self,bar,widget):
bar.lower(widget)
def vbar(self,ele, x, y, w, h, parent):
sw = 15 # Scrollbar 宽度
x = x + w - sw
vbar = Scrollbar(parent)
ele.configure(yscrollcommand=vbar.set)
vbar.config(command=ele.yview)
vbar.place(x=x, y=y, width=sw, height=h)
self.scrollbar_autohide(vbar,ele)
{{ ! /* 组件创建函数 */ }}
{{ @widgets => parent,widget }}
{{ ! /* 按钮 */ }}
{{ @if(widget.type == 'tk_button') }}
def __tk_button_{{ widget.id }}(self,parent):
btn = Button(parent, text="{{ widget.text }}", takefocus=False,{{ @bootstyle(widget) /}})
btn.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return btn
{{ /if }}
{{ ! /* 标签 */ }}
{{ @if(widget.type == 'tk_label') }}
def __tk_label_{{ widget.id }}(self,parent):
label = Label(parent,text="{{ widget.text }}",anchor="center", {{ @bootstyle(widget) /}})
label.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return label
{{ /if }}
{{ ! /* 输入框 */ }}
{{ @if(widget.type == 'tk_input') }}
def __tk_input_{{ widget.id }}(self,parent):
ipt = Entry(parent, {{ @bootstyle(widget) /}})
ipt.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return ipt
{{ /if }}
{{ ! /* 文本框 */ }}
{{ @if(widget.type == 'tk_text') }}
def __tk_text_{{ widget.id }}(self,parent):
text = Text(parent)
text.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
self.vbar(text, {{ widget.left }}, {{ widget.top }}, {{ widget.width }}, {{ widget.height }},parent)
return text
{{ /if }}
{{ ! /* 单选框 */ }}
{{ @if(widget.type == 'tk_radio_button') }}
def __tk_radio_button_{{ widget.id }}(self,parent):
rb = Radiobutton(parent,text="{{ widget.text }}",{{ @bootstyle(widget) /}})
rb.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return rb
{{ /if }}
{{ ! /* 多选框 */ }}
{{ @if(widget.type == 'tk_check_button') }}
def __tk_check_button_{{ widget.id }}(self,parent):
cb = Checkbutton(parent,text="{{ widget.text }}",{{ @bootstyle(widget) /}})
cb.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return cb
{{ /if }}
{{ ! /* 列表框 */ }}
{{ @if(widget.type == 'tk_list_box') }}
def __tk_list_box_{{ widget.id }}(self,parent):
lb = Listbox(parent)
{{ @each(widget.options) => option }}
lb.insert(END, "{{ option }}")
{{ /each }}
lb.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return lb
{{ /if }}
{{ ! /* 下拉选择框 */ }}
{{ @if(widget.type == 'tk_select_box') }}
def __tk_select_box_{{ widget.id }}(self,parent):
cb = Combobox(parent, state="readonly", {{ @bootstyle(widget) /}})
cb['values'] = ("{{ widget.options.join('","') | safe }}")
cb.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return cb
{{ /if }}
{{ ! /* 仪表盘 进度盘 */ }}
{{ @if(widget.type == 'tb_meter') }}
def __tb_meter_{{ widget.id }}(self,parent):
meter = Meter(parent,amountused=100, amounttotal=100, subtext="{{ widget.sub_text }}", metersize={{ widget.width }},
textleft="{{ widget.text_left }}", textright="{{ widget.text_right }}", interactive={{ widget.interactive ? 'True': 'False' }},
{{ @bootstyle(widget) /}})
meter.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return meter
{{ /if }}
{{ ! /* 图标组件 */ }}
{{ @if(widget.type == 'ext_icon') }}
def __ext_icon_{{ widget.id }}(self,parent):
icon = Icon(parent,icon_name="{{ widget.icon }}", size={{ Math.round(widget.width * 0.9) }}, color="{{ widget.color }}")
icon.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return icon
{{ /if }}
{{ ! /* 进度条 */ }}
{{ @if(widget.type == 'tk_progressbar') }}
def __tk_progressbar_{{ widget.id }}(self,parent):
progressbar = Progressbar(parent, orient={{ widget.width < widget.height ? 'VERTICAL' : 'HORIZONTAL' }},{{ @bootstyle(widget) /}})
progressbar.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return progressbar
{{ /if }}
{{ ! /* 滑块 */ }}
{{ @if(widget.type == 'tk_scale') }}
def __tk_scale_{{ widget.id }}(self,parent):
scale = Scale(parent, orient={{ widget.width < widget.height ? 'VERTICAL' : 'HORIZONTAL' }}, {{ @bootstyle(widget) /}})
scale.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return scale
{{ /if }}
{{ ! /* 表格 */ }}
{{ @if(widget.type == 'tk_table') }}
def __tk_table_{{ widget.id }}(self,parent):
# 表头字段 表头宽度
columns = {{ @tblcolumns(widget.columns,widget.width-1) /}}
tk_table = Treeview(parent, show="headings", columns=list(columns),{{ @bootstyle(widget) /}})
for text, width in columns.items(): # 批量设置列属性
tk_table.heading(text, text=text, anchor='center')
tk_table.column(text, anchor='center', width=width, stretch=False) # stretch 不自动拉伸
tk_table.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
self.vbar(tk_table, {{ widget.left }}, {{ widget.top }}, {{ widget.width }}, {{ widget.height }},parent)
return tk_table
{{ /if }}
{{ ! /* 框架 */ }}
{{ @if(widget.type == 'tk_frame') }}
def __tk_frame_{{ widget.id }}(self,parent):
frame = Frame(parent,{{ @bootstyle(widget) /}})
frame.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return frame
{{ /if }}
{{ ! /* 标签框架 */ }}
{{ @if(widget.type == 'tk_label_frame') }}
def __tk_label_frame_{{ widget.id }}(self,parent):
frame = LabelFrame(parent,text="{{ widget.text }}",{{ @bootstyle(widget) /}})
frame.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return frame
{{ /if }}
{{ ! /* tabs框架 */ }}
{{ @if(widget.type == 'tk_tabs') }}
def __tk_tabs_{{ widget.id }}(self,parent):
frame = Notebook(parent)
{{ @each(widget.tabs) => tab,i }}
self.widget_dic["{{ widget.type }}_{{ widget.id }}_{{ i }}"] = self.__tk_frame_{{ widget.id }}_{{ i }}(frame)
frame.add(self.widget_dic["{{ widget.type }}_{{ widget.id }}_{{ i }}"], text="{{ tab }}")
{{ /each }}
frame.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return frame
{{ @each(widget.tabs) => tab,i }}
def __tk_frame_{{ widget.id }}_{{ i }}(self,parent):
frame = Frame(parent)
frame.place(x={{ widget.left }}, y={{ widget.top }}, width={{ widget.width }}, height={{ widget.height }})
return frame
{{ /each }}
{{ /if }}
{{ /widgets }}
class Win(WinGUI):
def __init__(self):
super().__init__()
self.__event_bind()
{{ ! /* 配置菜单 */ }}
{{ @if(it.menus.length > 0) }}
self.config(menu=self.create_menu())
{{ /if }}
{{ ! /* 创建菜单相关方法 */ }}
{{ @if(it.menus.length > 0) }}
def create_menu(self):
menu = Menu(self,tearoff=False)
{{ @each(it.menus) => menu }}
{{ @if(menu?.children) }}
menu.add_cascade(label="{{ menu.name }}",menu=self.menu_{{ menu.id }}(menu))
{{ #else }}
menu.add_command(label="{{ menu.name }}",command=self.{{ menu.call }})
{{ /if }}
{{ /each }}
return menu
{{ /if }}
{{ @each(it.menus) => menu }}
{{ @if(menu?.children) }}
{{ @each(menu.children) => submenu }}
def menu_{{ menu.id }}(self,parent):
menu = Menu(parent,tearoff=False)
menu.add_command(label="{{ submenu.name }}",command=self.{{ submenu.call }})
return menu
{{ /each }}
{{ /if }}
{{ /each }}
{{ ! /* 创建菜单回调方法 */ }}
{{ @if(it.menus.length > 0) }}
{{ @each(it.menus) => menu }}
{{ @if(menu?.children) }}
{{ @each(menu.children) => submenu }}
def {{ submenu.call }}(self):
print("点击了菜单")
{{ /each }}
{{ #else }}
def {{ menu.call }}(self):
print("点击了菜单")
{{ /if }}
{{ /each }}
{{ /if }}
{{ ! /* 创建事件处理并绑定方法 */ }}
{{ @events=> ele }}
def {{ ele.func }}(self,evt):
print("{{ ele.evt | safe }}事件未处理:",evt)
{{ /events }}
def __event_bind(self):
{{ @events=> ele }}
{{ @if(ele.type == 'tk_win') }}
self.bind('{{ ele.evt | safe }}',self.{{ ele.func }})
{{ #else }}
self.widget_dic["{{ ele.type }}_{{ ele.id }}"].bind('{{ ele.evt | safe }}',self.{{ ele.func }})
{{ /if }}
{{ /events }}
pass
if __name__ == "__main__":
win = Win()
win.mainloop()