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的事件循环。
    整个应用程序的设计是为了提供一个工作流编辑器,用户可以添加、编辑和拖拽功能按钮,以及编辑每个功能按钮的参数。工具提示的添加是为了提供额外的信息,以便用户更好地理解每个功能按钮的作用。

代码

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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/778379.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大数据】—FIFA世界杯探索性分析(EDA)

引言 足球&#xff0c;作为全球最受欢迎的运动之一&#xff0c;拥有庞大的粉丝群体和深远的文化影响。自1930年首届FIFA世界杯举办以来&#xff0c;这项赛事已经成为全球体育盛事&#xff0c;吸引了数十亿观众的目光。世界杯不仅是各国足球技艺的较量&#xff0c;更是国家荣誉…

02STM32环境搭建新建工程

STM32环境搭建&新建工程 软件安装&#xff1a;开发方式&新建工程步骤&架构 个人心得 软件安装&#xff1a; 安装Keil5 MDK 安装器件支持包 软件注册 安装STLINK驱动 安装USB转串口驱动 开发方式&新建工程步骤&架构 STM32开发方式&#xff1a; 1.寄存器 …

笔记14:程序中的循环结构

生活中的循环现象&#xff1a; -日复一日&#xff0c;年复一年 -春夏秋冬&#xff0c;四季交替 -周日&#xff0c;周一&#xff0c;周二&#xff0c;周三&#xff0c;周四&#xff0c;周五&#xff0c;周六 -人生是一个轮回&#xff0c;多年后&#xff0c;又会回到最初的原点 …

APP渗透-android12夜神模拟器+Burpsuite实现

一、夜神模拟器下载地址&#xff1a;https://www.yeshen.com/ 二、使用openssl转换证书格式 1、首先导出bp证书 2、将cacert.der证书在kali中转换 使用openssl生成pem格式证书,并授予最高权限 openssl x509 -inform der -in cacert.der -out cacert.pem chmod 777 cacert…

容器:queue(队列)

以下是关于queue容器的总结 1、构造函数&#xff1a;queue [queueName] 2、添加、删除元素: push() 、pop() 3、获取队头/队尾元素&#xff1a;front()、back() 4、获取栈的大小&#xff1a;size() 5、判断栈是否为空&#xff1a;empty() #include <iostream> #include …

解决 MEX 文件 ‘xxx.mexw64‘ 无效: 找不到指定的模块。的问题

1.问题描述 在matlab R2021b中运行编译好后的gptoolbox工具箱中的函数[SVtemp,SFtemp,IF] selfintersect(V,F);报错如下 MEX 文件 E:\MATLAB_File\gptoolbox\mex\selfintersect.mexw64 无效: 找不到指定的模块。出错 offset_bunny (第 15 行) [SVtemp,SFtemp,IF] selfinter…

MATLAB-分类CPO-RF-Adaboost冠豪猪优化器(CPO)优化RF随机森林结合Adaboost分类预测(二分类及多分类)

MATLAB-分类CPO-RF-Adaboost冠豪猪优化器&#xff08;CPO&#xff09;优化RF随机森林结合Adaboost分类预测&#xff08;二分类及多分类&#xff09; 分类CPO-RF-Adaboost冠豪猪优化器&#xff08;CPO&#xff09;优化RF随机森林结合Adaboost分类预测&#xff08;二分类及多分类…

MySQL基础篇(三)数据库的修改 删除 备份恢复 查看连接情况

对数据库的修改主要指的是修改数据库的字符集&#xff0c;校验规则。 将test1数据库字符集改为gbk。 数据库的删除&#xff1a; 执行完该数据库就不存在了&#xff0c;对应数据库文件夹被删除&#xff0c;级联删除&#xff0c;里面的数据表全部被删除。 注意&#xff1a;不要随…

线程同步66666

1. 概述 当有多个线程访问同一个共享资源&#xff08;临界资源&#xff09;时&#xff0c;且不允许同时访问&#xff0c;那么就需要线程同步。常见的线程同步方式&#xff1a;互斥锁、读写锁、条件变量、信号量。 2. 互斥锁 互斥锁的方式可以简单概括为&#xff1a;锁定操作…

ros1仿真导航机器人 navigation

仅为学习记录和一些自己的思考&#xff0c;不具有参考意义。 1navigation导航框架 2导航设置过程 &#xff08;1&#xff09;启动仿真环境 roslaunch why_simulation why_robocup.launch &#xff08;2&#xff09;启动move_base导航、amcl定位 roslaunch why_simulation nav…

【OnlyOffice】桌面应用编辑器,插件开发大赛,等你来挑战

OnlyOffice&#xff0c;桌面应用编辑器&#xff0c;最近版本已从8.0升级到了8.1 从PDF、Word、Excel、PPT等全面进行了升级。随着AI应用持续的火热&#xff0c;OnlyOffice也在不断推出AI相关插件。 因此&#xff0c;在此给大家推荐一下OnlyOffice本次的插件开发大赛。 详细信息…

磁盘就是一个超大的Byte数组,操作系统是如何管理的?

磁盘在操作系统的维度看&#xff0c;就是一个“超大的Byte数组”。 那么操作系统是如何对这块“超大的Byte数组”做管理的呢&#xff1f; 我们知道在逻辑上&#xff0c;上帝说是用“文件”的概念来进行管理的。于是&#xff0c;便有了“文件系统”。那么&#xff0c;文件系统…

深圳晶彩智能ESP32-2432S028R实时观察LVGL9效果

深圳晶彩智能ESP32-2432S028R概述&#xff1a; 深圳晶彩智能出品ESP32-32432S028R为2.8寸彩色屏采用分辨率320x240彩色液晶屏&#xff0c;驱动芯片是ILI9431。板载乐鑫公司出品ESP-WROOM-32&#xff0c;Flash 4M。型号尾部“R”标识电阻膜的感压式触摸屏&#xff0c;驱动芯片是…

以腾讯为例,手把手教你搭建产品帮助中心

一个精心设计的产品帮助中心对于提高用户满意度和体验至关重要。腾讯&#xff0c;作为全球领先的互联网企业&#xff0c;通过其多样化的产品线&#xff08;包括微信、QQ、腾讯游戏、腾讯视频等&#xff09;吸引了亿万用户。下面将以腾讯为例&#xff0c;向您展示如何搭建一个高…

数据库系统原理 | 查询作业1

整理自博主本科《数据库系统原理》专业课自己完成的实验课查询作业&#xff0c;以便各位学习数据库系统概论的小伙伴们参考、学习。 *文中若存在书写不合理的地方&#xff0c;欢迎各位斧正。 专业课本&#xff1a; ​ ———— 本次实验使用到的图形化工具&#xff1a;Heidisql…

进程的控制-ps和kill命令

ps 查看进程信息 部分参数&#xff1a; a : 显示现行终端机下的所有程序&#xff0c;包括其他用户的程序 u: 以用户为主的格式来显示程序状况 x: 显示所有程序&#xff0c;不以 终端机来区分 kill 向指定的进程发送信号 kill 可将指定的信息送至程序。预设的信息为 SIG…

linux下高级IO模型

高级IO 1.高级IO模型基本概念1.1 阻塞IO1.2 非阻塞IO1.3 信号驱动IO1.4 IO多路转接1.5 异步IO 2. 模型代码实现2.1 非阻塞IO2.2 多路转接-selectselect函数介绍什么才叫就绪呢&#xff1f;demoselect特点 2.3 多路转接-pollpoll函数介绍poll优缺点demo 2.4 多路转接-epoll&…

24西安电子科技大学马克思主义学院—考研录取情况

01、马克思主义学院各个方向 02、24马克思主义学院近三年复试分数线对比 PS&#xff1a;马院24年院线相对于23年院线增加15分&#xff0c;反映了大家对于马克思主义理论学习与研究的热情高涨&#xff0c;也彰显了学院在人才培养、学科建设及学术研究等方面的不断进步与成就。 6…

集成学习(一)Bagging

前边学习了&#xff1a;十大集成学习模型&#xff08;简单版&#xff09;-CSDN博客 Bagging又称为“装袋法”&#xff0c;它是所有集成学习方法当中最为著名、最为简单、也最为有效的操作之一。 在Bagging集成当中&#xff0c;我们并行建立多个弱评估器&#xff08;通常是决策…

限时免费!国产Sora快手可灵Web网页端及全新功能上线!国货之光!

大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 快手可灵&#xff08;Kling&#xff09;这回是真的出息了&…