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()
相关推荐
深蓝海拓14 分钟前
Pyside6(PyQT5)中的QTableView与QSqlQueryModel、QSqlTableModel的联合使用
数据库·python·qt·pyqt
无须logic ᭄22 分钟前
CrypTen项目实践
python·机器学习·密码学·同态加密
百流34 分钟前
scala文件编译相关理解
开发语言·学习·scala
Channing Lewis35 分钟前
flask常见问答题
后端·python·flask
Channing Lewis37 分钟前
如何保护 Flask API 的安全性?
后端·python·flask
水兵没月2 小时前
钉钉群机器人设置——python版本
python·机器人·钉钉
Evand J2 小时前
matlab绘图——彩色螺旋图
开发语言·matlab·信息可视化
我想学LINUX3 小时前
【2024年华为OD机试】 (A卷,100分)- 微服务的集成测试(JavaScript&Java & Python&C/C++)
java·c语言·javascript·python·华为od·微服务·集成测试
深度混淆3 小时前
C#,入门教程(04)——Visual Studio 2022 数据编程实例:随机数与组合
开发语言·c#