HTML、Python、Brython、javascript - 在Brython上运行

3

使用Brython运行Python中的简单程序。

基础文件来自示例http://www.brython.info/gallery/pygame/chimp.html,但该文件无法正常工作。

在同一目录下有3个文件:Eventlist.htmlpy_VFS.jsbrython.js

py_VFS.js

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL py_VFS.js was not found on this server.</p>
</body></html>

brython.js:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL brython.js was not found on this server.</p>
</body></html>

Eventlist.html在以下代码行中的固定路径已修复:

<script type="text/javascript" src="external/brython/brython.js"></script>
<script type="text/javascript" src="external/brython/py_VFS.js"></script>

一个 Python 模块 (pygame 中的标准单元示例 eventlist.py) 被替换了。因此,Eventlist.html 的整个代码如下:

<html>

<head>

<script type="text/javascript" src="brython.js"></script>
<script type="text/javascript" src="py_VFS.js"></script>

<script type="text/python">
#!/usr/bin/env python

"""Eventlist is a sloppy style of pygame, but is a handy
tool for learning about pygame events and input. At the
top of the screen are the state of several device values,
and a scrolling list of events are displayed on the bottom.

This is not quality 'ui' code at all, but you can see how
to implement very non-interactive status displays, or even
a crude text output control.
"""

from pygame import *

ImgOnOff = []
Font = None
LastKey = None

def showtext(win, pos, text, color, bgcolor):
    textimg = Font.render(text, 1, color, bgcolor)
    win.blit(textimg, pos)
    return pos[0] + textimg.get_width() + 5, pos[1]


def drawstatus(win):
    bgcolor = 50, 50, 50
    win.fill(bgcolor, (0, 0, 640, 120))
    win.blit(Font.render('Status Area', 1, (155, 155, 155), bgcolor), (2, 2))

    pos = showtext(win, (10, 30), 'Mouse Focus', (255, 255, 255), bgcolor)
    win.blit(ImgOnOff[mouse.get_focused()], pos)

    pos = showtext(win, (330, 30), 'Keyboard Focus', (255, 255, 255), bgcolor)
    win.blit(ImgOnOff[key.get_focused()], pos)

    pos = showtext(win, (10, 60), 'Mouse Position', (255, 255, 255), bgcolor)
    p = '%s, %s' % mouse.get_pos()
    pos = showtext(win, pos, p, bgcolor, (255, 255, 55))

    pos = showtext(win, (330, 60), 'Last Keypress', (255, 255, 255), bgcolor)
    if LastKey:
        p = '%d, %s' % (LastKey, key.name(LastKey))
    else:
        p = 'None'
    pos = showtext(win, pos, p, bgcolor, (255, 255, 55))

    pos = showtext(win, (10, 90), 'Input Grabbed', (255, 255, 255), bgcolor)
    win.blit(ImgOnOff[event.get_grab()], pos)


def drawhistory(win, history):
    win.blit(Font.render('Event History Area', 1, (155, 155, 155), (0,0,0)), (2, 132))
    ypos = 450
    h = list(history)
    h.reverse()
    for line in h:
        r = win.blit(line, (10, ypos))
        win.fill(0, (r.right, r.top, 620, r.height))
        ypos -= Font.get_height()


def main():
    init()

    win = display.set_mode((640, 480), RESIZABLE)
    display.set_caption("Mouse Focus Workout")

    global Font
    Font = font.Font(None, 26)

    global ImgOnOff
    ImgOnOff.append(Font.render("Off", 1, (0, 0, 0), (255, 50, 50)))
    ImgOnOff.append(Font.render("On", 1, (0, 0, 0), (50, 255, 50)))

    history = []

    #let's turn on the joysticks just so we can play with em
    for x in range(joystick.get_count()):
        j = joystick.Joystick(x)
        j.init()
        txt = 'Enabled joystick: ' + j.get_name()
        img = Font.render(txt, 1, (50, 200, 50), (0, 0, 0))
        history.append(img)
    if not joystick.get_count():
        img = Font.render('No Joysticks to Initialize', 1, (50, 200, 50), (0, 0, 0))
        history.append(img)

    going = True
    while going:
        for e in event.get():
            if e.type == QUIT:
                going = False
            if e.type == KEYDOWN:
                if e.key == K_ESCAPE:
                    going = False
                else:
                    global LastKey
                    LastKey = e.key
            if e.type == MOUSEBUTTONDOWN:
                event.set_grab(1)
            elif e.type == MOUSEBUTTONUP:
                event.set_grab(0)
            if e.type == VIDEORESIZE:
                win = display.set_mode(e.size, RESIZABLE)

            if e.type != MOUSEMOTION:
                txt = '%s: %s' % (event.event_name(e.type), e.dict)
                img = Font.render(txt, 1, (50, 200, 50), (0, 0, 0))
                history.append(img)
                history = history[-13:]


        drawstatus(win)
        drawhistory(win, history)

        display.flip()
        time.wait(10)

    quit()


if __name__ == '__main__':
    main()

</script>
</head>
<body onload="brython({debug:1})">
  <div id="pydiv"></div>
</body>

</html>

当您运行Eventlist.html时,浏览器会显示一个空白页面。文件eventlist.py中的代码有效,结果如下所示:enter image description here因此,我希望在浏览器中获得类似的窗口。
1个回答

2
这几天我花了些时间尝试在浏览器中让Brython-PyGame运行起来,并得出以下结论:
  1. Brython-PyGame从未被完全实现。
  2. 由于PyGame和浏览器在用户交互建模方面存在根本差异,因此几乎不可能在Brython中实现一个完全工作的PyGame版本。
以下是详细信息: 未完成的实现 Brython-PyGame有许多未实现的函数。其中一些可以被认为是非关键性的(例如,模块transform.py完全缺失)。但其他一些则涉及到任何PyGame程序的核心。例如,event.py module中的所有非平凡函数,如event.get()event.wait(),都依赖于SDL.py中未实现的函数的调用,例如SDL_WaitEventAndReturn()SDL_PeepEvents()。没有一个非平凡的PyGame程序能够在没有这些函数作为其事件循环基础的情况下工作。 基本设计差异 event.wait()从未完全实现的事实并非巧合。这个函数涉及到PyGame和客户端Web编程之间概念设计差异的核心:
PyGame假定控制运行游戏的应用程序,这意味着它通常会阻塞主线程,直到发生感兴趣的事件。相比之下,JavaScript编程不允许阻塞主JS线程,因为此线程用于页面的UI渲染。如果您尝试阻塞此线程,浏览器将显示一个消息,说明页面已变得无响应,并建议用户关闭选项卡。相反,JS在事件发生时大量依赖于承诺和回调来运行。因此,在浏览器的客户端中实现阻塞调用(例如等待鼠标移动的事件)的调用是不可能的。此外,还有其他情况,PyGame以不允许JavaScript的方式使用阻塞调用。例如,请考虑以下看似无害的PyGame片段:
import pygame as pg
img = pg.image.load('flag.png')
screen.blit(img, (0,0))

这段代码加载一个图片文件,并在屏幕上呈现。在幕后,pg.image.load 命令会在文件读入内存时 阻塞。在 Brython-PyGame 中,实现尝试从给定的 URL 读取文件。然而,在 JavaScript 中,读取 URL 是一种非阻塞操作,因为所需的网络操作可能需要一段时间,我们不希望 UI 线程在完成之前被阻塞。在 JavaScript 中,类似的操作可以实现为以下内容:
var img = new Image();
ctx = getContextForSomeCanvas();
img.onload = function() {
  ctx.drawImage(img, 0, 0);
}
img.src = 'flag.png';

其中的 onload 回调确保只有在图像加载完成后才会执行 ctx.drawImage。将原来的 Python 代码转换成类似上述 JavaScript 的代码并不容易:它需要一些异步加载操作的幕后处理,这会延迟对 blit() 的调用直到图像被加载。即使这样可以工作,对于一个天真的 PyGame 程序员来说,这也很不直观,并且很容易在代码后面引起错误(例如,如果代码假设鼠标点击在图像上,即使它还没有加载)。在任何情况下,Brython-PyGame 实现不会实现这种幕后处理,导致上面的代码失败,因为图像将在加载之前被 blitted。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接