[英]What am I doing wrong while trying to call JS in pythoncef?
有人可以告訴我在第118行執行此JavaScript cefpython回調時我做錯了什么嗎?
# Tutorial example. Doesn't depend on any third party GUI framework.
# Tested with CEF Python v56.2+
from cefpython3 import cefpython as cef
import base64
import platform
import sys
import threading
# HTML code. Browser will navigate to a Data uri created
# from this html code.
HTML_code = """
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body,html { font-family: Arial; font-size: 11pt; }
div.msg { margin: 0.2em; line-height: 1.4em; }
b { background: #ccc; font-weight: bold; font-size: 10pt;
padding: 0.1em 0.2em; }
b.Python { background: #eee; }
i { font-family: Courier new; font-size: 10pt; border: #eee 1px solid;
padding: 0.1em 0.2em; }
</style>
<script>
function js_print(lang, event, msg) {
msg = "<b class="+lang+">"+lang+": "+event+":</b> " + msg;
console = document.getElementById("console")
console.innerHTML += "<div class=msg>"+msg+"</div>";
}
function js_callback_1(ret) {
js_print("Javascript", "html_to_data_uri", ret);
}
function js_callback_2(msg, py_callback) {
js_print("Javascript", "js_callback", msg);
py_callback("String sent from Javascript XY5C");
}
window.onload = function(){
js_print("Javascript", "python_property", python_property);
html_to_data_uri("test", js_callback_1);
external.test_multiple_callbacks(js_callback_2);
};
</script>
</head>
<body>
<div id="console"></div>
<canvas id="myCanvas" width="800" height="800"></canvas>
<script type="text/javascript">
function js_callback_1(ret) {
js_print("Javascript", "html_to_data_uri", ret);
}
function js_callback_2(msg, py_callback) {
js_print("Javascript", "js_callback", msg);
py_callback("String sent from Javascript 01XC");
}
window.onload = function(){
js_print("Javascript", "window.onload", "Called");
js_print("Javascript", "python_property", python_property);
js_print("Javascript", "navigator.userAgent", navigator.userAgent);
js_print("Javascript", "cefpython_version", cefpython_version.version);
html_to_data_uri("test", js_callback_1);
external.test_multiple_callbacks(js_callback_2);
};
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
//event listener
window.addEventListener("keydown", onKeyDown, false);
window.addEventListener("keyup", onKeyUp, false);
function onKeyDown(event) {
var keyCode = event.keyCode;
switch (keyCode) {
case 68: //d
keyD = true;
break;
case 83: //s
keyS = true;
break;
case 65: //a
keyA = true;
break;
case 87: //w
keyW = true;
break;
}
}
function onKeyUp(event) {
var keyCode = event.keyCode;
switch (keyCode) {
case 68: //d
keyD = false;
break;
case 83: //s
keyS = false;
break;
case 65: //a
keyA = false;
break;
case 87: //w
keyW = false;
py_callback("String sent from Javascript 89JX");
break;
}
}
//neccessary variables
var tickX = 10;
var tickY = 10;
var keyW = false;
var keyA = false;
var keyS = false;
var keyD = false;
//main animation function
function drawStuff() {
window.requestAnimationFrame(drawStuff);
var canvas = document.getElementById("myCanvas");
var c = canvas.getContext("2d");
c.clearRect(0, 0, 800, 800);
c.fillStyle = "blue";
c.fillRect(tickX, tickY, 100, 100);
if (keyD == true) {
tickX += 1;
}
if (keyS == true) {
tickY += 1;
}
if (keyA == true) {
tickX--;
}
if (keyW == true) {
tickY--;
}
}
window.requestAnimationFrame(drawStuff);
</script>
</body>
</html>
"""
#<body>
# <h1>Tutorial example</h1>
# <div id="console"></div>
#</body>
def main():
check_versions()
sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error
cef.Initialize()
set_global_handler()
browser = cef.CreateBrowserSync(url=html_to_data_uri(HTML_code),
window_title="Tutorial")
set_client_handlers(browser)
set_javascript_bindings(browser)
cef.MessageLoop()
cef.Shutdown()
def check_versions():
print("[tutorial.py] CEF Python {ver}".format(ver=cef.__version__))
print("[tutorial.py] Python {ver} {arch}".format(
ver=platform.python_version(), arch=platform.architecture()[0]))
assert cef.__version__ >= "56.2", "CEF Python v56.2+ required to run this"
def html_to_data_uri(html, js_callback=None):
# This function is called in two ways:
# 1. From Python: in this case value is returned
# 2. From Javascript: in this case value cannot be returned because
# inter-process messaging is asynchronous, so must return value
# by calling js_callback.
html = html.encode("utf-8", "replace")
b64 = base64.b64encode(html).decode("utf-8", "replace")
ret = "data:text/html;base64,{data}".format(data=b64)
if js_callback:
js_print(js_callback.GetFrame().GetBrowser(),
"Python", "html_to_data_uri",
"Called from Javascript. Will call Javascript callback now.")
js_callback.Call(ret)
else:
return ret
def set_global_handler():
# A global handler is a special handler for callbacks that
# must be set before Browser is created using
# SetGlobalClientCallback() method.
global_handler = GlobalHandler()
cef.SetGlobalClientCallback("OnAfterCreated",
global_handler.OnAfterCreated)
def set_client_handlers(browser):
client_handlers = [LoadHandler(), DisplayHandler()]
for handler in client_handlers:
browser.SetClientHandler(handler)
def set_javascript_bindings(browser):
external = External(browser)
bindings = cef.JavascriptBindings(
bindToFrames=False, bindToPopups=False)
bindings.SetProperty("python_property", "python_property defined in Python #X1HQ")
bindings.SetProperty("cefpython_version", cef.GetVersion())
bindings.SetFunction("html_to_data_uri", html_to_data_uri)
bindings.SetObject("external", external)
browser.SetJavascriptBindings(bindings)
def js_print(browser, lang, event, msg):
# Execute Javascript function "js_print"
browser.ExecuteFunction("js_print", lang, event, msg)
class GlobalHandler(object):
def OnAfterCreated(self, browser, **_):
# DOM is not yet loaded. Using js_print at this moment will
# throw an error: "Uncaught ReferenceError: js_print is not defined".
# We make this error on purpose. This error will be intercepted
# in DisplayHandler.OnConsoleMessage.
js_print(browser, "Python", "OnAfterCreated",
"This will probably never display as DOM is not yet loaded")
# Delay print by 0.5 sec, because js_print is not available yet
args = [browser, "Python", "OnAfterCreated",
"(Delayed) Browser id="+str(browser.GetIdentifier())]
threading.Timer(0.5, js_print, args).start()
class LoadHandler(object):
def OnLoadingStateChange(self, browser, is_loading, **_):
# This callback is called twice, once when loading starts
# (is_loading=True) and second time when loading ends
# (is_loading=False).
if not is_loading:
# Loading is complete. DOM is ready.
js_print(browser, "Python", "OnLoadingStateChange",
"Loading is complete")
class DisplayHandler(object):
def OnConsoleMessage(self, browser, message, **_):
# This will intercept js errors, see comments in OnAfterCreated
if "error" in message.lower() or "uncaught" in message.lower():
# Prevent infinite recurrence in case something went wrong
if "js_print is not defined" in message.lower():
if hasattr(self, "js_print_is_not_defined"):
print("Python: OnConsoleMessage: "
"Intercepted Javascript error: "+message)
return
else:
self.js_print_is_not_defined = True
# Delay print by 0.5 sec, because js_print may not be
# available yet due to DOM not ready.
args = [browser, "Python", "OnConsoleMessage",
"(Delayed) Intercepted Javascript error: <i>{error}</i>"
.format(error=message)]
threading.Timer(0.5, js_print, args).start()
browser.ExecuteJavascript("alert('The value for \"python_property\" is: ' + python_property);")
class External(object):
def __init__(self, browser):
self.browser = browser
def test_multiple_callbacks(self, js_callback):
"""Test both javascript and python callbacks."""
js_print(self.browser, "Python", "test_multiple_callbacks",
"Called from Javascript. Will call Javascript callback now.")
def py_callback(msg_from_js):
js_print(self.browser, "Python", "py_callback", msg_from_js)
js_callback.Call("String sent from Python H1T7", py_callback)
if __name__ == '__main__':
main()
我知道我可能使用了錯誤的語法,但是我嘗試了15種變體,但仍然無法弄清楚。 每個路由都會產生錯誤或無法更新。
(要清楚,我正在嘗試在JavaScript中按下'w'時用字符串定義一個變量,該變量也會在藍色方塊周圍移動。)
可能是您沒有正確設置一些變量, py_callback
python_property
和py_callback
,但在代碼上使用了它們。
下面這個代碼,你會看到python_property正在使用設置,
bindings.SetProperty("python_property", "This property was set in Python")
同樣在這里定義了其他一些函數,例如py_callback
,這些函數在您的代碼上被調用但從未定義。
def py_callback(msg_from_js):
js_print(self.browser, "Python", "py_callback", msg_from_js)
我怎么知道的 只需將所有代碼復制到純HTML文件中,然后打開控制台即可。 然后,當我遇到一些錯誤時,我知道了要尋找的地方。 那不是調試的好方法,但是也要把它保留在15種以上的版本中:D。
對代碼進行深入研究后,它表明您正在嘗試訪問一個名為py_callback
變量,該變量是js_callback_2
函數的局部變量。 因此,它會產生錯誤。
要傳遞數據,可以在External類上使用一個函數,該函數可以被調用並用於傳遞數據。
somevar = 'whatever'
class External(object):
def __init__(self, browser):
self.browser = browser
def set_variable_value(self, key, value):
somevar = value;
print(somevar)
# globals()[key] = value;
# print(globals()[key])
現在,如果我在python代碼的較早地方定義了somevar,則一旦我調用set_variable_value
函數,它將被更新。 如果使用globals()
,則可以從該函數修改任何全局變量。
要調用它,我們必須在js代碼中傳入2個參數,而不是定義3個參數,因為cefpython將用完一個參數。
case 87: //w
keyW = false;
external.test_multiple_callbacks(js_callback_2);
external.set_variable_value('hello','world'); // <-- notice param count
break;
如果您粘貼第118行,將會有所幫助:
py_callback("String sent from Javascript 89JX");
問題是在Python端沒有綁定到javascript的函數。 您必須在Python中定義此類函數,然后通過調用bindings.SetFunction
在set_javascript_bindings
函數中將其bindings.SetFunction
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.