说明
这段代码是一个使用Tkinter编写的图形用户界面(GUI)应用程序,它用于编辑工作流。以下是代码的主要部分和功能的说明:
Tooltip
类:这是一个自定义类,用于创建一个工具提示窗口,当鼠标悬停在指定的Tkinter小部件上时显示。它使用Tkinter的Toplevel
窗口来创建工具提示,并且当鼠标离开时销毁这个窗口。WorkflowEditor
类:这是应用程序的主类,它负责创建和布局窗口,添加功能按钮,并处理与按钮相关的操作。它包含一个函数add_function
,用于在功能框中添加新按钮,并设置它们的位置和功能。ParamEditor
和ParamEditorNew
类:这两个类是参数编辑器,它们是弹出窗口,允许用户编辑工作流中函数的参数。ParamEditor
用于编辑函数名和功能参数名,而ParamEditorNew
用于编辑输入/输出方向和参数名。on_drag_start
和on_drag_motion
函数:这些函数用于处理鼠标拖拽事件,允许用户拖拽功能框中的按钮并改变它们的位置。if __name__ == "__main__":
块:这是Python脚本的入口点,它创建一个主窗口,并实例化WorkflowEditor
类,启动Tkinter的事件循环。
整个应用程序的设计是为了提供一个工作流编辑器,用户可以添加、编辑和拖拽功能按钮,以及编辑每个功能按钮的参数。工具提示的添加是为了提供额外的信息,以便用户更好地理解每个功能按钮的作用。
代码
python
import tkinter as tk
from tkinter import simpledialog, ttk
class Tooltip:
def __init__(self, widget, text):
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.enter)
self.widget.bind("<Leave>", self.leave)
self.tooltip_window = None
def enter(self, event=None):
x, y, _, _ = self.widget.bbox("insert")
x += self.widget.winfo_rootx() + 25
y += self.widget.winfo_rooty() + 25
self.tooltip_window = tk.Toplevel(self.widget)
self.tooltip_window.wm_overrideredirect(True)
self.tooltip_window.wm_geometry(f"+{x}+{y}")
label = ttk.Label(self.tooltip_window, text=self.text, background="#ffffe0", borderwidth=1, relief="solid")
label.pack()
def leave(self, event=None):
if self.tooltip_window:
self.tooltip_window.destroy()
self.tooltip_window = None
class WorkflowEditor:
def __init__(self, root):
self.root = root
self.root.title("Workflow Editor")
# 创建左侧的功能框
self.functions_frame = tk.Frame(self.root, width=600, height=600, bg='white', borderwidth=2, relief="solid")
self.functions_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.functions_frame_list = dict()
add_function_button = tk.Button(self.functions_frame, text="Add Function", command=self.add_new_function)
add_function_button.pack(side=tk.BOTTOM, fill=tk.BOTH)
# 创建右侧的工作流编排框
# self.workflow_frame = tk.Canvas(self.root, width=600, height=600, bg='white',borderwidth=2, relief="solid")
# self.workflow_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
# 添加一些示例功能
self.add_function('Function1', {'input': {'param1': 'value1', 'param2': 'value2'}, 'output': {'result': ''}})
self.add_function('Function2', {'input': {'param1': 'value1', 'param2': 'value2'}, 'output': {'result': ''}})
self.add_function('Function3', {'input': {'param1': 'value1', 'param2': 'value2'}, 'output': {'result': ''}})
self.func_count = 3
def add_function(self, name, params):
# 创建一个功能按钮,可以点击编辑参数
functions_frame = tk.Frame(self.root)
functions_frame.pack()
# 创建9个按钮,并使用Grid布局管理器将它们放置在3x3的网格中
for row in range(3):
for col in range(3):
if row == 1 and col == 1:
button = tk.Button(functions_frame, text=name)
button.widgetName = "{}_{}".format(row, col)
button.grid(row=row, column=col, padx=5, pady=5)
button.bind('<Button-3>', lambda event, p=params, r=row, c=col: self.edit_params(p, name, r, c))
else:
button = tk.Button(functions_frame, text=f"edit")
button.widgetName = "{}_{}".format(row, col)
button.grid(row=row, column=col, padx=5, pady=5)
button.bind('<Button-3>', lambda event, p=params, r=row, c=col: self.edit_params_new(p, name, r, c))
# button = tk.Button(self.functions_frame, text=name)
# button.pack(fill=tk.X)
functions_frame.bind("<Button-1>", on_drag_start)
functions_frame.bind("<B1-Motion>", on_drag_motion)
self.functions_frame_list[name] = functions_frame
def add_new_function(self):
# 弹出对话框,请求用户输入新功能的名称
name = simpledialog.askstring("Function{}".format(self.func_count), "Enter function name:")
if name:
self.func_count += 1
# 创建一个默认的参数字典
params = {'input': {}, 'output': {'result': ''}}
# 添加新功能到界面
self.add_function("Function{}".format(self.func_count) + name, params)
# 打印新功能的参数,以便于调试
print(f"Added new function '{name}': {params}")
def edit_params(self, params, name, r, c):
# 弹出对话框,允许用户编辑参数
dialog = ParamEditor(self.root, params)
dialog.name = name
self.root.wait_window(dialog.top)
# 获取编辑后的参数
# new_params = dialog.get_params()
# 增加函数功能说明
Tooltip(self.functions_frame_list[name].children["!button{}".format(r * 3 + c + 1)],
params["func_name"]+":"+params["tip"])
# 设置颜色 设计名字
self.functions_frame_list[name].children["!button{}".format(r * 3 + c + 1)].config(bg=params["arg"])
def edit_params_new(self, params, name, r, c):
print(name)
# 弹出对话框,允许用户编辑参数
dialog = ParamEditorNew(self.root, params)
dialog.name = name
dialog.r = r
dialog.c = c
self.root.wait_window(dialog.top)
# 获取编辑后的参数
# new_params = dialog.get_params()
colors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange', 'cyan', 'pink', 'brown']
# self.functions_frame.children[0].config(bg=colors[1])
# self.functions_frame.children["!button"].config(bg=colors[1])
if r * 3 + c + 1 == 1:
self.functions_frame_list[name].children["!button"].config(bg=params["arg"])
self.functions_frame_list[name].children["!button"].config(text=params["s"])
else:
self.functions_frame_list[name].children["!button{}".format(r * 3 + c + 1)].config(bg=params["arg"])
self.functions_frame_list[name].children["!button{}".format(r * 3 + c + 1)].config(text=params["s"])
class ParamEditor:
def __init__(self, parent, params):
self.params = params
self.top = tk.Toplevel(parent)
self.top.title("参数编辑")
# 创建输入和输出标签框架
self.input_frame = tk.LabelFrame(self.top, text="函数名", padx=5, pady=5)
self.input_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.output_frame = tk.LabelFrame(self.top, text="功能参数名", padx=5, pady=5)
self.output_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# self.output_frame1 = tk.LabelFrame(self.top, text="输入/输出参数名", padx=5, pady=5)
# self.output_frame1.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 添加输入参数
self.add_parameter_entry(self.input_frame)
# 添加输出参数
# self.add_parameter_option(self.output_frame, tk.StringVar(), options=["io_选项A", "io_选项B", "io_选项C", "io_选项D"])
self.add_parameter_text(self.output_frame)
# 创建确认按钮
ok_button = tk.Button(self.top, text="OK", command=self.ok)
ok_button.pack()
def add_parameter_entry(self, frame):
if self.params.get("func_name") is None:
self.entry = tk.Entry(frame)
self.entry.pack()
else:
self.entry = tk.Entry(frame, textvariable=self.params["func_name"])
self.entry.pack()
def add_parameter_text(self, frame):
self.text_box = tk.Text(frame, height=10, width=50)
self.text_box.pack()
def ok(self):
# 更新参数并关闭对话框
self.params["func_name"] = self.entry.get()
self.params["tip"] = self.text_box.get("1.0", tk.END)
self.top.destroy()
return self.params
class ParamEditorNew:
def __init__(self, parent, params):
self.params = params
self.top = tk.Toplevel(parent)
self.top.title("参数编辑")
# 创建输入和输出标签框架
self.input_frame = tk.LabelFrame(self.top, text="输入/输出方向", padx=5, pady=5)
self.input_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.output_frame = tk.LabelFrame(self.top, text="输入/输出参数名", padx=5, pady=5)
self.output_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# self.output_frame1 = tk.LabelFrame(self.top, text="输入/输出参数名", padx=5, pady=5)
# self.output_frame1.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 添加输入参数
self.add_parameter_option(self.input_frame, tk.StringVar(), options=["s_^", "s_v", "s_<", "s_>"])
# 添加输出参数
# self.add_parameter_option(self.output_frame, tk.StringVar(), options=["io_选项A", "io_选项B", "io_选项C", "io_选项D"])
self.add_parameter_option(self.output_frame, tk.StringVar(),
options=["arg_"+i for i in ['red', 'blue', 'green', 'yellow', 'purple', 'orange', 'cyan', 'pink', 'brown']])
# 创建确认按钮
ok_button = tk.Button(self.top, text="OK", command=self.ok)
ok_button.pack()
def on_select_option(self, selected_var):
# 当用户选择一个OptionMenu时,这个函数会被调用
def callback(value):
print(f"你选择了:{value}")
self.params[value.split("_")[0]] = value.split("_")[1]
return callback
def add_parameter_option(self, frame, selected_var, options=["选项A", "选项B", "选项C", "选项D"]):
# 设置一个默认值
selected_var.set("请选择")
# 创建下拉单选菜单
dropdown = tk.OptionMenu(frame, selected_var, *options, command=self.on_select_option(selected_var))
dropdown.pack()
def ok(self):
# 更新参数并关闭对话框
self.top.destroy()
def get_params(self):
return self.params
def on_drag_start(event):
"""开始拖拽"""
widget = event.widget
widget._drag_start_x = event.x
widget._drag_start_y = event.y
def on_drag_motion(event):
"""拖拽中"""
widget = event.widget
x = widget.winfo_x() - widget._drag_start_x + event.x
y = widget.winfo_y() - widget._drag_start_y + event.y
widget.place(x=x, y=y)
if __name__ == "__main__":
root = tk.Tk()
app = WorkflowEditor(root)
root.mainloop()