使用tkinter制作tkinterUI编辑器
前言
最近更新了几个小功能,这篇统一记录一下,包括复制粘贴控件,将xml读取到当前编辑的控件中,鼠标右键点击树结点弹出右键菜单,还有一些报错就不记录了,下一个目标是实现多重选择功能。
一、快捷键的添加
-
发现忘了记录快捷键的处理逻辑,这里记录一下,代码如下,tkinterEditor.py
############################################### hot key ################################################### def init_hot_key(self): """ 初始化快捷键 :return: None """ self.master.bind("<Control-s>", lambda event: self.save_gui()) self.master.bind("<Control-o>", lambda event: self.open_gui()) self.master.bind("<Control-n>", lambda event: self.new_gui()) self.master.bind("<Control-p>", lambda event: self.new_project()) self.master.bind("<Control-Delete>", lambda event: self.delete_control()) for k in ("Up", "Down", "Left", "Right"): self.master.bind("<Control-{0}>".format(k), partial(self.move_control, k))
-
修改EditorTree.py,因为我暂时不想处理树的上下左右逻辑(treeview有默认的上下左右事件),所以先break掉,不处理
def key_press(self, event): if event.keysym in ("Up", "Down", "Left", "Right"): return "break"
-
修改EditorPropertyList.py,因为comboBox也有默认的上下事件,所以也先不处理
def key_click(self, event): if event.keysym in ("Up", "Down"): return "break"
二、复制粘贴控件
-
修改default.ini,添加复制粘贴的菜单
[menu] edit = delete_control#delete,move_up#ctrl+up,move_down#ctrl+down,move_left#ctrl+left,move_right#ctrl+right,copy#ctrl+comma,paste#ctrl+period
-
修改tkinterEditor.py
from copy import deepcopy 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.copied_component = None # 复制的控件信息 self.init_frame() def create_control(self, quick_name, gui_name, property_dict=None): """ 创建控件 :param quick_name: 快捷按钮名字 :param gui_name: 控件名字 :return: None """ if self.get_selected_component() is None: return child_master = self.get_selected_component().component.get_child_master() if time.time() - self.created_time > 2: self.created_pos_x = 0 self.created_pos_y = 0 control_name = self.create_random_name(gui_name) prop = { "background": "white", "x": self.created_pos_x, "y": self.created_pos_y, "component_name": control_name, "gui_type": gui_name, } if child_master["background"]== "white": prop["background"] = "grey" # 创建一个frame套在真正的控件外面 frame_prop = { "background": child_master["background"], "highlightcolor": "red", } frame, info = create_default_component(child_master, "Frame", "None", frame_prop, False) # 创建控件 if property_dict is not None: property_dict["component_name"] = control_name property_dict["is_main"] = 0 property_dict["x"] = prop["x"] property_dict["y"] = prop["y"] component = create_component_from_dict(frame, property_dict) else: component, property_dict = create_default_component(frame, gui_name, control_name, prop) frame.configure(width=component.winfo_reqwidth() + 4, height=component.winfo_reqheight() + 4) # 以下控件需要重新修改宽和高 if gui_name in ("Progressbar", "Scrollbar", "Separator"): frame.configure(width=int(property_dict["width"]) + 4, height=int(property_dict["height"]) + 4) frame.place_configure(x=property_dict["x"], y=property_dict["y"], anchor=property_dict["anchor"]) component.place_configure(x=0, y=0, anchor="nw") self.on_component_create(self.file_tab_window.get_cur_tab(), True, component, property_dict, child_master) self.created_time = time.time() self.created_pos_x += 10 self.created_pos_y += 10 def copy(self): """ 复制控件 :return: None """ edit_component = self.get_selected_component() if edit_component is None: return self.copied_component = deepcopy(edit_component.get_component_info()) def paste(self): """ 粘贴控件 :return: None """ if self.copied_component is None: return gui_type = self.copied_component["gui_type"] self.create_control(gui_type, gui_type, deepcopy(self.copied_component)) def init_hot_key(self): """ 初始化快捷键 :return: None """ self.master.bind("<Control-s>", lambda event: self.save_gui()) self.master.bind("<Control-o>", lambda event: self.open_gui()) self.master.bind("<Control-n>", lambda event: self.new_gui()) self.master.bind("<Control-p>", lambda event: self.new_project()) self.master.bind("<Control-Delete>", lambda event: self.delete_control()) self.master.bind("<Control-comma>", lambda event: self.copy()) self.master.bind("<Control-period>", lambda event: self.paste()) for k in ("Up", "Down", "Left", "Right"): self.master.bind("<Control-{0}>".format(k), partial(self.move_control, k))
-
快捷键使用逗号和句号是因为编辑属性的时候会用到ctrl c和v,为了不冲突而使用的
-
create_control函数里添加了粘贴的逻辑,处理了下控件位置和名字啥的
-
复制粘贴的时候一定要用深拷贝,一开始忘了导致出现了严重的问题
三、将xml读取到当前编辑的控件中
-
有了这个功能就能重复利用以前已经创建好的ui,不用再新创建了
-
修改default.ini,添加快捷功能按钮
[quick_btn] LoadXml = LoadXml
-
修改tkinterEditor.py
def init_quick_btn(self): """ 初始化功能快捷按键 :return: None """ prop = {"y": 5, "activebackground": "red", "borderwidth": 3, "width": 0,} for quick_name in self.config_parser.options("quick_btn"): gui_name = self.config_parser.get("quick_btn", quick_name) prop.update({"text": quick_name}) btn = self.quick_list.add_col(prop, False) btn.bind("<ButtonRelease-1>", partial(self.on_quick_btn_click, quick_name, gui_name)) self.quick_list.do_layout_col() def on_quick_btn_click(self, quick_name, gui_name, event): """ 点击快捷键 :param gui_name:模块名 :return:None """ if quick_name == "LoadXml": self.load_xml_to_edit_component() return self.create_control(quick_name, gui_name) def load_xml_to_edit_component(self): """ 读取xml后创建到当前编辑的component中 :return: None """ edit_component = self.get_selected_component() if edit_component is None: return file_path = askopenfilename(title=u"选择文件", filetypes=[("xml files", "xml"), ("all files", "*")]) if not file_path: return cur_tab = self.file_tab_window.get_cur_tab() components = self.load_from_xml(edit_component.component.get_child_master(), file_path, False, partial(self.on_component_create, cur_tab, False)) for parent_name, component_info in components.items(): if component_info.get("is_main", "0") == "1": component_info["is_main"] = 0 edit_component.component_info.setdefault("children", []).append(component_info) self.refresh_tree() self.treeview.tree.selection_set(edit_component.name)
-
读取ui后我重新刷新了一下树,因为我又懒的处理添加逻辑了
四、treeview鼠标右键选中结点功能
-
修改EditorTree.py,添加鼠标右键事件
class EditorTree(ScrollCanvas): def __init__(self, master=None, cnf={}, **kw): ScrollCanvas.__init__(self, master, cnf, **kw) self.root_index = 0 # 根节点索引 self.node_num = 0 # 所有节点个数 self.data = {} # 额外存储的数据 self.editor = None # 编辑器 self.on_select_tree = None # 选中树的回调 self.on_select_tree_3 = None # 右键树 def set_on_select_tree_3(self, on_select_tree_3): self.on_select_tree_3 = on_select_tree_3 def create_tree(self): """ 创建树 :return: None """ property_dict = { "height": 14, "show": "tree", "selectmode": "browse", } tree_view, info = create_default_component(self.slide_window, "Treeview", "tree", property_dict) tree_view.bind('<ButtonRelease-1>', self.select_tree) tree_view.bind('<ButtonRelease-3>', self.select_tree_3) tree_view.bind('<Key>', self.key_press) def select_tree_3(self, event): if self.on_select_tree_3 != None: self.on_select_tree_3(event)
-
修改tkinterEditor.py
def init_treeview(self): """ 初始化treeview :return: None """ # 修改第一列的宽度 self.treeview.tree.column("#0", width=int(self.treeview["width"]) - 20) self.treeview.set_on_select_tree(self.on_select_tree) self.treeview.set_on_select_tree_3(self.on_select_tree_3) self.treeview.set_editor(self) def on_select_tree(self, event): """ 选中树节点 :param event: event :return: None """ index = self.treeview.tree.focus() component = self.treeview.get_data_by_index(index) if not component: return if index == "root": return self.on_edit_component_selected(component, True, None) def on_select_tree_3(self, event): """ 右键树 :param event: event :return: None """ row = event.widget.identify_row(event.y) if not row: return if row == "root": return event.widget.selection_set(row) component = self.treeview.get_data_by_index(row) if not component: return self.on_edit_component_selected(component, True, None) self.right_edit_menu.post(event.x_root, event.y_root)
-
添加这个功能的时候发现点击根节点有报错,在这里处理一下
-
使用identify_row函数找到鼠标右键点击的节点,然后选中这个节点,之后弹出鼠标右键菜单