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()
相关推荐
健康的猪几秒前
golang的cgo的一点小心得
开发语言·后端·golang
夜夜敲码22 分钟前
C语言教程(十六): C 语言字符串详解
c语言·开发语言
cooldream200923 分钟前
深入理解MVP架构:让UI层与业务逻辑完美分离的设计模式
ui·设计模式·架构·系统架构师
拖孩26 分钟前
【Nova UI】十一、组件库中 Icon 组件的测试、使用与全局注册全攻略
前端·javascript·vue.js·ui·sass
宋康28 分钟前
C语言结构体和union内存对齐
c语言·开发语言
逢生博客33 分钟前
使用 Python 项目管理工具 uv 快速创建 MCP 服务(Cherry Studio、Trae 添加 MCP 服务)
python·sqlite·uv·deepseek·trae·cherry studio·mcp服务
居然是阿宋38 分钟前
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
android·开发语言·kotlin
堕落似梦40 分钟前
Pydantic增强SQLALchemy序列化(FastAPI直接输出SQLALchemy查询集)
python
Cao1234567893211 小时前
简易学生成绩管理系统(C语言)
c语言·开发语言
The Future is mine1 小时前
C# new Bitmap(32043, 32043, PixelFormat.Format32bppArgb)报错:参数无效,如何将图像分块化处理?
开发语言·c#