python GUI库 EEL + VUE.js 开发环境配置 联调

 eel开发环境启动的服务器默认端口是8000,如果前端界面的开发也是直接在EEL开发环境中进行,一切好办。但如果前端用vue,则需要另外启动专用的vue开发环境的服务器(Vue CLI (npm run serve)默认端口是8080,Vite (npm run dev)默认端口是5173)。

 那怎么同步联调开发呢?

核心操作有两点:

1、python代码中的eel.start() 参数配置指定启动页为vue环境的入口页

2、vue页面中引入eel.js的时候,引用路径为eel环境的eel.js , 以及把websocket的host设为eel环境的host。

# main.pyimport eel@eel.expose
def say_hello_py(x):print("Hello from %s" % x)"""开发环境:
1、python开发环境的eel.start()参数:设置启动页面为vue开发环境的服务端口5173,
2、vue开发环境中的public/index.html里引用eel.js时,路径是引用python eel环境的eel.js
3、vue开发环境中的public/index.html里设置websocket的服务器为python eel所启动的那个服务器。生产环境:
和正常的一样使用
"""
def start_eel(environment):"""判断当前是开发环境还是生产环境,选择不同的eel.start()参数配置"""if environment == 'develop':    # 开发环境directory = 'src'           # 注意!这个值对应的是EEL服务器的文件夹,不是VUE服务器的文件夹app ='chrome'start_page = {'port': 5173}       # 指向:http://localhost:5173/eel_kwargs = dict(          # 设置  http://localhost:9000 为eel服务器mode=app,host="localhost",port=9000,)else:                           # 生产环境directory = 'web'app = 'chrome'start_page = 'index.html'eel_kwargs = dict(mode=app,port=0,size=(1280, 800),)eel.init(directory)eel.start(start_page, **eel_kwargs)if __name__ == "__main__":print("启动python...")start_eel('develop')

// vue 的 public/index.html<%if(process.env.NODE_ENV === 'production'){ %>
<script type="text/javascript" src="/eel.js"></script>
<%}else{%>
<script type=text/javascript src="http://localhost:9000/eel.js"></script>
<script>window.eel.set_host("ws://localhost:9000");
</script>
<%}%>

<!-- vue 中 public/index.html--><!DOCTYPE html>
<html><head><title>Hello, World!</title><script type=text/javascript src="http://localhost:9000/eel.js"></script>
<script>window.eel.set_host("ws://localhost:9000");
</script><script type="text/javascript">eel.expose(say_hello_js); // Expose this function to Pythonfunction say_hello_js(x) {const msg = "Hello from " + xdocument.getElementById("msgbox").innerHTML=msg;}eel.say_hello_py("Javascript World!"); // Call a Python function</script></head><body>Hello, World!<button onclick="eel.say_hello_py('Javascript Button!')">调用Python函数</button><p id="msgbox"></p><button onclick="say_hello_js('Javascript Button!')">调用JS函数</button></body>
</html>

==========

踩坑小记:

    eel.init(directory)

当使用5173端口作前端服务时, eel.init(directory)  的directory 这个配置项对应的文件夹应该是VUE开发环境的本地文件夹。如果VUE开发环境不在本机上,你可以在本地构建一个文件夹,把需要用到的js函数的函数名放入这个文件夹中即可。

我一开始没有留意,结果是界面可以成功启动,界面启动过程没有报错,网页端调用python函数也成功,但python端调用js函数就报错提示:[AttributeError: module 'eel' has no attribute 'say_hello_js'] ,把eel.init(directory)的directory配置为vue服务的本地目录就成功了。

甚至你可以专门建一个目录,这个目录只存放一个文本文件,把所有暴露的js函数名以eel.expose(js_function_name) 的形式记录到一个文件中,并以.js为扩展名命名,也可以。

//expose_js_function_name.jseel.expose(say_hello_js); 
eel.expose(my_js_function_1); 
eel.expose(my_js_function_2); 
eel.expose(my_js_function_3); 
eel.expose(my_js_function_4); 

跟踪了一下源代码,发现确实是通过遍历该文件夹及其子目录的全部指定扩展名的文件,并通过语法解析器 EXPOSED_JS_FUNCTIONS (基于PyParsing构建)进行匹配。

EXPOSED_JS_FUNCTIONS的解释规则是:用正则表达式匹配,解析得到函数名,这些函数名被存储在js_functions这个集合中。

得到这些js函数名后,通过_mock_js_function() 构建同名函数,构建的这个函数对于eel这个类来说是全局函数,所以对于main.py来说,就是【eel.同名函数】,就可以通过eel.js_function_name() 调用了。

# 如果程序未被PyInstaller打包成exe,则返回path的绝对路径,否则exe创建的临时资源目录_MEIPASS
def _get_real_path(path: str) -> str:if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, path) # type: ignore # sys._MEIPASS is dynamically added by PyInstallerelse:return os.path.abspath(path)'''
当你使用 PyInstaller 将脚本+资源打包成一个exe后。运行exe时,会动态创建一个临时目录(通常是在系统的临时文件夹中),并将可执行文件内部的所有资源解压到这个临时目录。sys._MEIPASS 就是这个临时目录的路径。
'''
def init(path: str, allowed_extensions: List[str] = ['.js', '.html', '.txt', '.htm','.xhtml', '.vue'], js_result_timeout: int = 10000) -> None:global root_path, _js_functions, _js_result_timeoutroot_path = _get_real_path(path)js_functions = set()for root, _, files in os.walk(root_path):    # 遍历它的子目录for name in files:if not any(name.endswith(ext) for ext in allowed_extensions):continuetry:with open(os.path.join(root, name), encoding='utf-8') as file:contents = file.read()expose_calls = set()matches = EXPOSED_JS_FUNCTIONS.parseString(contents).asList() # 对文件进行解释,把【暴露给python的js函数】匹配出来。for expose_call in matches:# Verify that function name is validmsg = "eel.expose() call contains '(' or '='"assert rgx.findall(r'[\(=]', expose_call) == [], msgexpose_calls.add(expose_call)        # 收集此文件的暴露函数js_functions.update(expose_calls)        # 收集全部文件的暴露函数except UnicodeDecodeError:pass    # Malformed file probably_js_functions = list(js_functions)for js_function in _js_functions:_mock_js_function(js_function)        # 将找到的JS函数名称保存起来,并准备在 websocket 连接时使用_js_result_timeout = js_result_timeout

===============================================

对于eel.start() 参数配置中的start_page参数。

根据作者官方github上的资料,eel.start()的第一个参数是启动页的html文件名(入口页面),是字符串。为什么可以接收一个dict变量{'port':5173}呢?

追踪了一下源代码,发现其值为dict类型时,可以支持的参数包含了协议scheme 、域host 、端口port 、路径path 这几个参数

其值为字符串时,字符串应该为base_url 之后的访问路径。

代码追踪:def start(*start_urls: str, **kwargs: Any)  -->  show(*start_urls) -->brw.open(list(start_urls), _start_args) --> open(start_pages: Iterable[Union[str, Dict[str, str]]], options: OptionsDictT) --> _build_urls(start_pages: Iterable[Union[str, Dict[str, str]]], options: OptionsDictT) -->_build_url_from_dict(page, options)

def _build_url_from_dict(page: Dict[str, str], options: OptionsDictT) -> str:scheme = page.get('scheme', 'http')host = page.get('host', 'localhost')port = page.get('port', options["port"])path = page.get('path', '')if not isinstance(port, (int, str)):raise TypeError("'port' option must be an integer")return '%s://%s:%d/%s' % (scheme, host, int(port), path)def _build_url_from_string(page: str, options: OptionsDictT) -> str:if not isinstance(options['port'], (int, str)):raise TypeError("'port' option must be an integer")base_url = 'http://%s:%d/' % (options['host'], int(options['port']))return base_url + page

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS7中如何docker-compose

在 CentOS 7 上安装 docker-compose 需要几个步骤 步骤 1: 安装 Docker 首先&#xff0c;确保你已经安装了 Docker。如果没有安装&#xff0c;可以通过以下命令安装&#xff1a; sudo yum update -y sudo yum install -y yum-utils sudo yum-config-manager --add-repo http…

攻防世界(CTF)~web-supersqli(详细解题思路)

题目介绍 题目描述“随便注” 先看一下是否存在注入 判断闭合方式 输入1’ and 11-- -正常回显 输入1and 12-- -无回显,确认是单引号闭合 看一下列数 输入1 order by 2-- - 有回显 输入1 order by 3-- - 报错&#xff0c;由此判断两列 使用union联合注入发现select被过滤了&a…

WMS仓储管理系统如何让仓库管理有过程

在当今竞争激烈的商业环境中&#xff0c;WMS仓储管理系统的智能化与过程化管理显得尤为重要。一个具有过程管理的WMS仓储管理系统不仅能够帮助企业实时监控、分析和调度仓库作业&#xff0c;还能显著提升作业效率和成本控制能力。下面&#xff0c;我们就来深入探讨一下这种“有…

流媒体zlmediakit

目标&#xff1a; 流媒体部署 内容&#xff1a; 使用开源流媒体zlmediakit docker搭建&#xff1a; docker run -d -p 10000:10000 -p 10000:10000/udp -p 1935:1935 -p 8080:80 -p 8554:554 -p 8443:443 -p 8000:8000/udp -p 9000:9000/udp -p 30000-30050:30000-30050…

IT Tools

vs & vscode工具 Vs Extensions & Remote Development Vs Extensions Remote-SSH VSCode远程连接到Linux并实现免密码登录 Git Graph C cppreference.com cplusplus 镜像站点 用于下载 QT, Ubuntu, 清华镜像站点 CMake Download Documents Cmake 构建QT …

IO系列(三) - 文件读写操作介绍

一、摘要 在之前的文章中&#xff0c;我们了解到在 Java I/O 体系中&#xff0c;File 类是唯一代表磁盘文件本身的对象。 File 类定义了一些与平台无关的方法来操作文件&#xff0c;包括检查一个文件是否存在、创建、删除文件、重命名文件、判断文件的读写权限是否存在、设置…

揿针在医保上叫什么?

点击文末领取揿针的视频教程跟直播讲解 创新型皮内针&#xff08;揿针&#xff09;——医保甲类产品 皮内针&#xff08;揿针&#xff09;技术属于重点推广的中医适宜技术&#xff0c;是将特制的小型针具固定于腧穴部位的皮内或皮下做较长时间留针的一种方法&#xff0c;称“…

2024年 C++音视频开发学习路线(ffmpeg/rtsp/srs/webrtc/hls)

在音视频工作领域&#xff0c;很多人可能会陷入徘徊和迷茫的境地。音视频的知识纷繁复杂&#xff0c;自己学习非常困难&#xff0c;既需要非常扎实的基础知识&#xff0c;又需要有很多的工程经验&#xff1b;不知道如何学&#xff0c;怎样才能查漏补缺自己的技术短板。 对于音…

QT C++ widget layout 嵌套 例子2

在上篇文章中描述了实中套虚&#xff08;用setLayout&#xff09;&#xff0c;虚中套实&#xff08;用addWidget&#xff09;。 本文再加1条&#xff0c;虚中套虚&#xff08;用addLayout&#xff09;。 所谓虚中套虚&#xff0c;是layout 套 layout 。 另外用循环代码生成从…

记录接口请求偶发504 Gateway Time-out问题

项目场景&#xff1a; 我们将服务部署到A公司服务器中&#xff0c;使用了共五台服务器&#xff0c;分别是&#xff1a;1.NG服务器 2.日志服务器 3.缓存服务器 4.应用服务器1 5.应用服务器2 。而请求过来首先到达的是他们的物理代理服务器&#xff0c;然后再转发请求到我们的ng…

【Neo4jJDK开箱即用的安装全流程】

neo4j:命令行本地访问loclhost neo4j:命令行本地访问loclhost2 neo4j操作 Neo4j桌面版数据库导出导入 Neo4j安装与配置以及JDK安装与配置教程&#xff08;超详细&#xff09; Neo4j 安装、使用教程 Neo4j安装教程 Neo4J桌面版的配置和连接Pycharm jdk-neo对应版本 JDK ORACLE中…

数据结构(四)————二叉树和堆(中)

制作不易&#xff0c;三连支持一下呗&#xff01;&#xff01;&#xff01; 文章目录 前言一、堆的概念及结构二、堆的实现三.堆的应用 总结 前言 CSDN 这篇博客介绍了二叉树中的基本概念和存储结构&#xff0c;接下来我们将运用这些结构来实现二叉树 一、堆的概念及结构 1…

招聘公司要求跳槽时间间隔不能太短,我的简历不符合要求,怎么办?

很多招聘公司要求就很奇葩,什么三五原则,什么二一原则,意思就是,你几年内,不能在超过几家公司内任职。你就说多奇葩啊,他们都不能保证自己的员工在自己公司干多久,甚至裁掉刚干了半年的员工,也是他们干出来的事,然后他们还好意思有这种奇葩要求。 目录 1 虚假的双向选…

OpenPCDet算法的网络结构及工作原理

OpenPCDet是一个用于三维点云目标检测的开源算法库。它提供了完整的目标检测流程&#xff0c;包括数据预处理、网络模型、损失函数、后处理等。OpenPCDet基于PyTorch框架实现&#xff0c;并针对点云数据进行了深度优化&#xff0c;以实现高效的目标检测和定位。 OpenPCDet的目…

SpringMVC 注解详解

SpringMVC 注解详解 1. 引言 SpringMVC 是 Spring 框架中的 Web 层解决方案&#xff0c;它通过注解的方式来简化 MVC 模式的实现。本篇将详细介绍 SpringMVC 中常用的注解及其用法。 2. SpringMVC 注解分类 SpringMVC 的注解主要分为以下几类&#xff1a; 2.1 核心注解 C…

用sunoAI写粤语歌的方法,博主已经亲自实践可行

粤语歌还是很好听的&#xff0c;那么如何使用suno进行粤语歌的创作呢&#xff1f; 本文和大家进行分享下如何进行粤语歌曲的创作。 访问地址如下&#xff08;电脑端/手机端一个地址&#xff09;&#xff1a; ​https://suno3.cn/#/?i8NCBS8_WXTT 在微信浏览器中也可以直接…

css 案例 横向滚动渐变

效果 完整代码&#xff1a; <template><view class"content"><view class"tab"><view class"tab-item" v-for"(item,index) in tab" :key"index" click"handlerTab(index)":class"ind…

winserver系统设置图片查看器

新建 .bat 批处理执行文件&#xff0c;内容如下&#xff1a; echo off&cd&color 0a&cls echo Set Win10 Photo Viewer reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".jpg" /t REG_SZ /d Photo…

MySQL——利用变量进行查询操作

新建链接&#xff0c;自带world数据库&#xff0c;里面自带city表格。 DQL # MySQL利用变量进行查询操作 set cityNameHaarlemmermeer; select * from city where NamecityName;# 多个结果查询 set cityName1Haarlemmermeer; set cityName2Breda; set cityName3Willemstad; s…

Mysql--期末复习

目录 一.变量 1.系统变量 global session 2.用户自定义变量 3.局部变量 二.触发器 1.pysx函数(销售)拼音缩写触发器 2.goods维护(存储过程) 3.xkglxt 4.订单延期 一.变量 1.系统变量 global session 2.用户自定义变量 1.不用提前声明&#xff0c;使用时直接 变量…