使用tkinter制作tkinterUI编辑器
前言
这篇文章记录一下工程的创建,到这篇为止基本功能就都记录完了,之后有时间会加一些扩展功能。
一、修改tkinterEditor.py
import shutil
class tkinterEditor(componentMgr):
def __init__(self, master, gui_path):
componentMgr.__init__(self, master)
self.config_parser = ToolConfigParser()
self.config_parser.read("default.ini", encoding="utf-8-sig")
self.load_from_xml(master, gui_path, True)
self.theme = EDITOR_THEME_DEFAULT # 主题
self.right_edit_menu = None # 鼠标右键edit菜单
self.edit_components = {} # 存储可编辑的控件
self.selected_component = None # 当前被选中的控件
self.created_time = 0 # 创建控件时的时间
self.created_pos_x = 0 # 创建控件时的坐标x
self.created_pos_y = 0 # 创建控件时的坐标y
self.is_new_project_show = True # 创建新project界面是否显示
self.init_frame()
def init_frame(self):
"""
初始化ui
:return: None
"""
self.init_menu()
self.init_theme()
self.init_file_tab_window()
self.init_property_list()
self.init_treeview()
self.init_quick_btn()
self.init_top_level()
def new_project(self):
"""
新项目
:return: None
"""
self.change_new_project_ui()
##################################################### top level ############################################
def init_top_level(self):
"""
初始化top_level
:return: None
"""
self.top_level.protocol("WM_DELETE_WINDOW", self.change_new_project_ui)
self.top_level.resizable(width=False, height=False)
self.top_level.positionfrom(who="program")
self.top_level.children.get("btn_browse", None).bind("<Button-1>", self.on_top_level_browse_click)
self.top_level.children.get("btn_cancel", None).bind("<Button-1>", self.on_top_level_cancel_click)
self.top_level.children.get("btn_ok", None).bind("<Button-1>", self.on_top_level_ok_click)
self.change_new_project_ui()
def change_new_project_ui(self):
"""
打开关闭new_project界面
:return: None
"""
if self.is_new_project_show:
self.is_new_project_show = False
self.top_level.withdraw()
self.top_level.master.master.wm_attributes('-disabled', False)
return
self.is_new_project_show = True
self.top_level.deiconify()
self.top_level.master.master.wm_attributes('-disabled', True)
def on_top_level_browse_click(self, event):
"""
点击browse
:param event: event
:return: None
"""
location = askdirectory()
if not location:
return
self.entry_location.delete(0, "end")
self.entry_location.insert(0, location)
def on_top_level_cancel_click(self, event):
"""
点击取消
:param event: event
:return: None
"""
self.change_new_project_ui()
self.top_level.master.master.deiconify()
def on_top_level_ok_click(self, event):
"""
点击ok
:param event: event
:return: None
"""
# 获取项目名
name = self.entry_name.get()
if not name:
print("must insert name")
return
# 获取项目目录
location = self.entry_location.get()
if not location:
print("must insert location")
return
# 创建项目文件夹
new_path = os.path.join(location, name)
os.mkdir(new_path)
# 创建py文件
self.create_project_py(new_path, name)
# 拷贝文件
self.copy_file(new_path)
# 创建gui文件
file_path = os.path.join(new_path, name)
self.new_gui(file_path, None, "frame_" + name)
# 关闭界面
self.change_new_project_ui()
self.top_level.master.master.deiconify()
def create_project_py(self, file_path, file_name):
"""
创建py文件
:param file_path:文件夹路径
:param file_name:文件名字
:return:None
"""
self.create_init_py(file_path)
self.create_main_py(file_path, file_name)
@staticmethod
def create_init_py(file_path):
"""
创建init.py
:param file_path:文件夹路径
:return:None
"""
file_name = os.path.join(file_path, "init.py")
with open(file_name, 'w', encoding='utf-8') as f:
f.write("# -*- coding: UTF-8 -*-\n")
@staticmethod
def create_main_py(file_path, name):
"""
创建main.py
:param file_path:文件夹路径
:param name:文件名字
:return:None
"""
file_name = os.path.join(file_path, name + ".py")
with open(file_name, 'w', encoding='utf-8') as f:
f.write(
"# -*- coding: UTF-8 -*-\n\n"
"import os\n"
"from tkinter import *\n"
"from componentMgr import componentMgr\n\n\n"
"class {0}(componentMgr):\n\n"
" def __init__(self, master, gui_path):\n"
" componentMgr.__init__(self, master)\n"
" self.load_from_xml(master, gui_path, True)\n\n\n"
"def main():\n"
" root = Tk()\n"
" path = os.path.join(os.getcwd(), '{1}.xml')\n"
" {2}(root, path)\n"
" root.mainloop()\n\n\n"
"if __name__ == \"__main__\":\n"
" main()\n".format(name, name, name)
)
@staticmethod
def copy_file(file_path):
"""
拷贝文件
:param file_path:文件路径
:return:None
"""
cur_path = os.getcwd()
mgr_path = os.path.join(cur_path, "componentMgr.py")
tool_path = os.path.join(cur_path, "toolXmlParser.py")
component_path = os.path.join(cur_path, "componentBase.py")
property_path = os.path.join(cur_path, "componentProperty.py")
shutil.copy(mgr_path, os.path.join(file_path, "componentMgr.py"))
shutil.copy(tool_path, os.path.join(file_path, "toolXmlParser.py"))
shutil.copy(component_path, os.path.join(file_path, "components.py"))
shutil.copy(property_path, os.path.join(file_path, "componentProperty.py"))
说明:
-
导入shutil用于复制文件
-
change_new_project_ui函数用于打开与关闭创建工程界面
-
新加一个componentBase.py用于拷贝,新创建的工程不需要导入我自己加的控件,代码如下:
#!/usr/bin/python # -*- coding: utf-8 -*- import componentProperty from tkinter import * from tkinter.ttk import Combobox, Treeview, Separator, Progressbar from componentProperty import update_all_property, get_default_component_info def create_component_from_dict(master, component_info): """ 根据字典里面给定的属性创建控件 :param master: 父控件 :param component_info: 控件信息 :return: 创建的控件 """ gui_type = component_info["gui_type"] class_name = getattr(sys.modules[__name__], gui_type) component = class_name(master, name=component_info["component_name"]) update_all_property(component, component_info, gui_type) return component def create_default_component(master, component_type, component_name, prop=None, use_name=True): """ 创建默认控件 :param master: 父控件 :param component_type: 控件类型 :param component_name: 控件名字 :param prop: 需要更新的属性 :param use_name: 是否使用控件名字 :return: 控件 """ class_name = getattr(sys.modules[__name__], component_type) if use_name: component = class_name(master, name=component_name) else: component = class_name(master) component_info = get_default_component_info(component_type, prop) update_all_property(component, component_info, component_type) return component, component_info