python ui 工作流完善功能

说明

这段代码是一个使用Tkinter编写的图形用户界面(GUI)应用程序,它用于编辑工作流。以下是代码的主要部分和功能的说明:

  1. Tooltip类:这是一个自定义类,用于创建一个工具提示窗口,当鼠标悬停在指定的Tkinter小部件上时显示。它使用Tkinter的Toplevel窗口来创建工具提示,并且当鼠标离开时销毁这个窗口。
  2. WorkflowEditor类:这是应用程序的主类,它负责创建和布局窗口,添加功能按钮,并处理与按钮相关的操作。它包含一个函数add_function,用于在功能框中添加新按钮,并设置它们的位置和功能。
  3. ParamEditorParamEditorNew类:这两个类是参数编辑器,它们是弹出窗口,允许用户编辑工作流中函数的参数。ParamEditor用于编辑函数名和功能参数名,而ParamEditorNew用于编辑输入/输出方向和参数名。
  4. on_drag_starton_drag_motion函数:这些函数用于处理鼠标拖拽事件,允许用户拖拽功能框中的按钮并改变它们的位置。
  5. 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()
相关推荐
茫茫人海一粒沙1 分钟前
Python 代码编写规范
开发语言·python
原野心存2 分钟前
java基础进阶知识点汇总(1)
java·开发语言
林浩2332 分钟前
Python——异常处理机制
python
程序猿阿伟4 分钟前
《C++高效图形用户界面(GUI)开发:探索与实践》
开发语言·c++
暗恋 懒羊羊12 分钟前
Linux 生产者消费者模型
linux·开发语言·ubuntu
数据分析螺丝钉28 分钟前
力扣第240题“搜索二维矩阵 II”
经验分享·python·算法·leetcode·面试
五味香29 分钟前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
梓䈑1 小时前
【C语言】自定义类型:结构体
c语言·开发语言·windows
鱼跃鹰飞1 小时前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试