实现效果
完整代码
from flask import flask, render_template, request, jsonify import sys from io import stringio import contextlib import subprocess import importlib import threading import time import ast import re app = flask(__name__) restricted_packages = { 'tkinter': '抱歉,在线编译器不支持 tkinter,因为它需要图形界面环境。请在本地运行需要gui的代码。', 'tk': '抱歉,在线编译器不支持 tk/tkinter,因为它需要图形界面环境。请在本地运行需要gui的代码。', 'pygame': 'pygame将被转换为web版本运行' # 不再限制pygame,而是转换它 } def convert_tkinter_to_web(code): """将tkinter代码转换为web等效实现""" # 解析python代码 tree = ast.parse(code) # 提取窗口属性 window_props = { 'title': 'python gui', 'width': '700', 'height': '500', 'buttons': [], 'labels': [], 'entries': [], 'layout': [] } # 用于存储函数定义 functions = {} # 首先收集所有函数定义 for node in ast.walk(tree): if isinstance(node, ast.functiondef): functions[node.name] = ast.unparse(node) # 分析代码中的tkinter组件 for node in ast.walk(tree): if isinstance(node, ast.assign): if isinstance(node.value, ast.call): # 提取窗口标题 if hasattr(node.value.func, 'attr') and node.value.func.attr == 'tk': for subnode in ast.walk(tree): if isinstance(subnode, ast.call) and hasattr(subnode.func, 'attr'): if subnode.func.attr == 'title' and len(subnode.args) > 0: window_props['title'] = ast.literal_eval(subnode.args[0]) elif subnode.func.attr == 'geometry' and len(subnode.args) > 0: geom = ast.literal_eval(subnode.args[0]) match = re.match(r'(\d+)x(\d+)', geom) if match: window_props['width'] = match.group(1) window_props['height'] = match.group(2) # 提取按钮 elif hasattr(node.value.func, 'attr') and node.value.func.attr == 'button': button = {'text': 'button', 'command': none} for kw in node.value.keywords: if kw.arg == 'text': button['text'] = ast.literal_eval(kw.value) elif kw.arg == 'command': # 处理不同类型的command if isinstance(kw.value, ast.name): # 简单的函数名 button['command'] = kw.value.id elif isinstance(kw.value, ast.lambda): # lambda表达式 button['command'] = f"lambda_{len(window_props['buttons'])}" functions[button['command']] = ast.unparse(kw.value) else: # 其他情况,尝试转换为字符串 try: button['command'] = ast.unparse(kw.value) except: button['command'] = 'unknown_command' window_props['buttons'].append(button) # 提取标签 elif hasattr(node.value.func, 'attr') and node.value.func.attr == 'label': label = {'text': ''} for kw in node.value.keywords: if kw.arg == 'text': try: label['text'] = ast.literal_eval(kw.value) except: # 如果不是字面量,尝试直接转换为字符串 label['text'] = ast.unparse(kw.value) window_props['labels'].append(label) # 提取输入框 elif hasattr(node.value.func, 'attr') and node.value.func.attr == 'entry': try: entry_id = node.targets[0].id except: entry_id = f"entry_{len(window_props['entries'])}" window_props['entries'].append({'id': entry_id}) # 生成web等效代码 web_code = f""" <!doctype html> <div class="tk-window" style="width: {window_props['width']}px; height: {window_props['height']}px;"> <div class="tk-title-bar">{window_props['title']}</div> <div class="tk-content"> """ # 添加标签 for label in window_props['labels']: web_code += f' <div class="tk-label">{label["text"]}</div>\n' # 添加输入框 for entry in window_props['entries']: web_code += f' <input type="text" class="tk-entry" id="{entry["id"]}">\n' # 添加按钮 for button in window_props['buttons']: command = button['command'] if button['command'] else '' web_code += f' <button class="tk-button" onclick="tkbuttonclick(\'{command}\')">{button["text"]}</button>\n' web_code += """ </div> </div> <script> window.pythonfunctions = { """ # 添加python函数定义 for func_name, func_code in functions.items(): web_code += f" '{func_name}': {func_code},\n" web_code += """}; </script> """ return web_code def convert_pygame_to_web(code): """将pygame代码转换为web canvas实现""" web_code = """ <canvas id="pygame-canvas" style="border: 1px solid #000;"></canvas> <script> const canvas = document.getelementbyid('pygame-canvas'); const ctx = canvas.getcontext('2d'); // 设置画布大小 canvas.width = 800; canvas.height = 600; // 模拟 pygame 的基本功能 const pygame = { display: { set_mode: (size) => { canvas.width = size[0]; canvas.height = size[1]; return canvas; }, update: () => { // canvas 自动更新 }, flip: () => { // canvas 自动更新 } }, draw: { rect: (surface, color, rect) => { ctx.fillstyle = `rgb(${color[0]},${color[1]},${color[2]})`; ctx.fillrect(rect[0], rect[1], rect[2], rect[3]); }, circle: (surface, color, pos, radius) => { ctx.beginpath(); ctx.fillstyle = `rgb(${color[0]},${color[1]},${color[2]})`; ctx.arc(pos[0], pos[1], radius, 0, math.pi * 2); ctx.fill(); } }, event: { get: () => [], // 简化的事件处理 pump: () => {} }, init: () => {}, quit: () => {}, time: { clock: function() { return { tick: (fps) => 1000/fps }; } } }; // 转换后的python代码 function rungame() { try { // 这里将插入转换后的游戏代码 %python_code% } catch (error) { console.error('game error:', error); } } // 启动游戏循环 rungame(); </script> """ # 处理 python 代码 try: tree = ast.parse(code) # 转换 python 代码为 javascript js_code = convert_pygame_code_to_js(tree) web_code = web_code.replace('%python_code%', js_code) return web_code except exception as e: return f"<div class='error'>转换错误: {str(e)}</div>" def convert_pygame_code_to_js(tree): """将 python ast 转换为 javascript 代码""" js_code = [] for node in ast.walk(tree): if isinstance(node, ast.import): continue # 跳过导入语句 elif isinstance(node, ast.assign): # 转换赋值语句 if hasattr(node.value, 'func') and isinstance(node.value.func, ast.attribute): if node.value.func.attr == 'set_mode': js_code.append(f"const screen = pygame.display.set_mode([{node.value.args[0].elts[0].n}, {node.value.args[0].elts[1].n}]);") elif isinstance(node, ast.while): # 转换游戏主循环 js_code.append("function gameloop() {") # ... 处理循环体 js_code.append(" requestanimationframe(gameloop);") js_code.append("}") js_code.append("gameloop();") return "\n".join(js_code) def install_package(package): """自动安装缺失的包""" # 检查是否是受限制的包 if package.lower() in restricted_packages: raise importerror(restricted_packages[package.lower()]) try: importlib.import_module(package) except importerror: try: # 尝试使用 pip 安装包 subprocess.check_call([sys.executable, "-m", "pip", "install", package]) except subprocess.calledprocesserror as e: raise exception(f"安装包 {package} 失败: {str(e)}") def timeout_handler(): """强制终止超时的代码执行""" raise timeouterror("代码执行超时(最大执行时间:5秒)") @app.route('/') def index(): return render_template('index.html') @app.route('/execute', methods=['post']) def execute_code(): code = request.json.get('code', '') try: # 检测是否包含pygame代码 if 'pygame' in code: web_code = convert_pygame_to_web(code) return jsonify({ 'status': 'success', 'output': '', 'gui': web_code }) # 检测是否包含tkinter代码 elif 'tkinter' in code or 'tk' in code: web_code = convert_tkinter_to_web(code) return jsonify({ 'status': 'success', 'output': '', 'gui': web_code }) # 非gui代码正常执行 output_buffer = stringio() with contextlib.redirect_stdout(output_buffer): exec(code, globals(), {}) output = output_buffer.getvalue() return jsonify({ 'status': 'success', 'output': output if output else '程序执行完成,没有输出' }) except exception as e: return jsonify({ 'status': 'error', 'output': f'错误: {str(e)}' }) if __name__ == '__main__': app.run(debug=true)
以上就是使用python开发在线编辑器的详细内容,更多关于python在线编辑器的资料请关注代码网其它相关文章!
发表评论