SL4A _R6 / Python4android_R4 webViewShow NullPointerException on simple example code - python

I'm trying to get a HTML Gui on my simple SL4A Python app. the only thing I need to perform is ask the user for 1 input string at the start of my app.
For debugging purposes I started of simple. Unfortunately even this won't function.
Any idea's what's wrong here? (I've tried several pieces of code like this and all have the same issue)
Python code:
import android
loop = True
droid = android.Android()
droid.webViewShow('/sdcard/sl4a/scripts/screen.html')
while loop:
res = droid.waitForEvent('data')
if res:
print str(res)
HTML code
<html>
<head>
<script>
var droid = new Android();
var fiets = function() {
droid.postEvent("data", document.getElementById("gsm").value);
}
</script>
</head>
<body onload:"fiets()">
<form onsubmit="fiets(); return false;">
<label for="say">What would you like to say?</label>
<input type="text" id="gsm" value="99999999" />
<input type="submit" value="Store" />
</form>
</body>
</html>
the error message is repeatedly (the number 3114 is incremental):
java.lang.NullPointerException
Result(id=3114, result=None, error=u'java.lang.NullPointerException')
update:
http://www.mithril.com.au/android/doc/EventFacade.html
As we go I read waitForEvent is deprecated in r4. I should use eventWaitFor instead.
This takes the error away but doesn't make the example function. Python script prints nothing.
update2:
droid.postEvent should become droid.eventPost
droid.waitForEvent('data') should become droid.waitForEvent('data')
In javascript and python.
Problem Solved

Related

HTML Output in Pyscript

I was experimenting in Pyscript and I tried to print an HTML table, but it didn't work. It seems to delete the tags and mantain just the plain text.
Why is that? I tried to search online, but being a new technology i didn't find much.
This is my code:
<py-script>
print("<table>")
for i in range (2):
print("<tr>")
for j in range (2):
print("<td>test</td>")
print("</tr>")
print("</table>")
</py-script>
And this is the output I get:
I tried to replace the print() method with the pyscript.write() method, but it didn't work too.
I dig in source code pyscript.py
and at this moment works for me only code similar to JavaScript
For example this adds <h1>Hello</h1>
<div id="output"></div>
<py-script>
element = document.createElement('h1')
element.innerText = "Hello"
document.getElementById("output").append(element)
</py-script>
Full working code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PyScript Demo</title>
<!--<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />-->
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div id="output"></div>
<py-script>
element = document.createElement('h1')
element.innerText = "Hello"
document.getElementById("output").append(element)
</py-script>
</body>
</html>
EDIT:
After digging in source code I found that pyscript.js runs function htmlDecode() which removes all tags from code in <py-script> (and probably it also removes tags when you load code from file) and this makes problem.
See Pyscript issue: [BUG] print() doesn't output HTML tags. · Issue #347 · pyscript/pyscript
Some workaround is to use some replacement - ie. {{ }} instead of < > in code - and later use code to replace it back to < >
print( "{{h1}}Hello{{/h1}}".replace("{{", "<").replace("}}", ">") )
or more universal - using function for this
def HTML(text):
return text.replace("{{", "<").replace("}}", ">")
print( HTML("{{h1}}Hello{{/h1}}") )
pyscript.write(some_id, HTML("{{h1}}Hello{{/h1}}") )
document.getElementById(some_id).innerHTML = HTML("{{h1}}Hello{{/h1}}")
Sometimes problem can be also pyscript.css which redefines some items and ie. <h1> looks like normal text.
One solution is to remove pyscript.css.
Other solution is to use classes from pyscript.css like in examples/index.html
<h1 class="text-4xl font-bold">Hello World</h1>
which means
print( HTML('{{h1 class="text-4xl font-bold"}}Hello{{/h1}}') )

Data seem not to update when refreshing the page in python bottle?

I'm running a script that shows up some data in python bottle, one of it is signal strength that I'd like to show in real time. When I refresh the page the value doesn't change so I have to rerun the server in order to update that signal strength. I've tried ajax but it seems that it doesn't work.
What should I use to make this to work?
EDIT: The variables are lists that come from another file.
iplist = [192.168.1.1, 192.168.1.2]
hostlist = [android234567, android677896]
maclist = [a1:b2:c3:d4:e5:f6, a1:b2:c3:d4:e5:f6]
signallist = [-56, 23]
.
#app.route('/')
def index():
info={'iplist': iplist, 'maclist': maclist, 'signallist': signallist, 'hostlist': hostlist}
tpl = '''
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script type="text/javascript">
function ajax(){
var req = new XMLHttpRequest();
req.onreadystatechange = function(){
if (req.readyState == 4 && req.status == 200) {
document.getElementById('signallist').innerHTML = req.responseText;
}
}
req.open('REQUEST', '../connectedDevices.py', true);
req.send();
}
(function(){ajax();}, 1000);
</script>
</head>
<body onload="ajax();">
<table>
<tr>
<td>IP address</td>
<td>Hostname</td>
<td>MAC address</td>
<td>Signal</td>
</tr>
%for i in range(len(maclist)):
<tr>
<td>{{iplist[i]}}</td>
<td>{{hostlist[i]}}</td>
<td>{{maclist[i]}}</td>
<td id="signallist">{{signallist[i]}}</td>
</tr>
%end
</table>
</body>
</html>
'''
return template(tpl, info)
This prints a chart where it shows Ip, host, mac and signal which the one that I want to get updated in real time.
Bottle caches the templates. So if you are feeding values in during the template creation, it will cache those values.
from bottle import TEMPLATES
TEMPLATES.clear()
Will reset those.
However, you really should think about where your data is coming and leverage websockets. gevent has a great websocket library and works great with bottle to make your code async. With a little work and javascript you can query your api and feed data real time into your code.

Methods on linking a HTML Tornado server and Python file

This is my sample HTML file
<html>
<head>
<title>
</title>
</head>
<body>
<form action="">
Value a:<br>
<input type="text" name="Va">
<br>
Value b:<br>
<input type="text" name="Vb">
<br><br>
<input type="submit">
</form>
<textarea rows="4" cols="10">
</textarea>
<p>
</p>
</body>
</html>
And a given template Tornado server code:(I also need help on the explanation of each section of the following code)
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.gen
import tornado.options
tornado.options.parse_command_line()
class APIHandler(tornado.web.RequestHandler):
#tornado.web.asynchronous
def get(self):
self.render('template.html')
#tornado.gen.engine
def post(self):
try:
num = int(self.get_argument('num'))
except:
num = 5
self.render('template.html')
app = tornado.web.Application([(r"/next_rec",APIHandler),])
if __name__ == "__main__":
server = tornado.httpserver.HTTPServer(app)
server.bind(48763)
server.start(5)
tornado.ioloop.IOLoop.current().start()
and finally my python code:
if __name__ == '__main__':
a = int(raw_input())
b = int(raw_input())
print a+b
I am using a simple 'a+b' function to test out this feature. But my problem is I can't figure out a way to link them together. So my ultimate goal is to click on the "Submit" button on the HTML, pass on two values to the Tornado server, use it as input in my python script and finally show the output in the text area of the HTML or on another page. I'm know there are tons of information on the web, but I'm completely new to Tornado (near 0 knowledge) and most of them I can't really understand. Help on methods or keywords for search is much appreciated, thank you very much. (please keep answers as basic as possible, it will help a lot, thanks!)
First of all you should check the official documentation. It is quite simple and it targets the newcomers.
Also in this short guide, the sections of a similar code as your is being explained with simplicity.
Now for your code:
On your template you need to specify that the form should send a post request on submit by adding <form method="post" id="sum_form">
Also you need to make sure that you will be submit the data added in the form on an event: $("#sum_form").submit();
On your post method you need to read the passed numbers from your client's form, add them and then send them back to the template as a parameter.
For example:
def post(self):
numA = int(self.get_argument('Va'))
numB = int(self.get_argument('VB'))
sumAB = numA + numB
self.render('template.html',sumAB=sumAB)
In you template.html you need to add a field where you will display the passed sum as a jinja variable : {{sumAB}}

form["x"] throws a KeyError

I'm working on an assignment and we are to create a HTML order form then execute the info by python to create a second customer receipt.
Here is the error msg:
Traceback (most recent call last):
File "F:\Assignment 3\page.py", line 17, in <module>
print "<p>Customer Name:", form["custName"].value, "</p>"
File "C:\Python27\lib\cgi.py", line 540, in __getitem__
raise KeyError, key
KeyError: 'custName'
THE HTML:
<form action="page.py">
<div class="personalinfohead">
<p>Personal Information:</p>
</div>
<div class="personalinfo">
<div>Full name:
<input type="text" name="custName" size="20" />
</div>
<div>Email address:
<input type="text" name="custEmail" size="50" />
</div>
<div>Street address:
<input type="text" name="custAdd" size="50" />
</div>
<div>City:
<input type="text" name="custCity" size="15" />
</div>
<div>Province:
<input type="text" name="custProv" size="2" maxlength="2" />
</div>
<div>Postal code:
<input type="text" name="custPostal" size="6" maxlength="6" />
</div>
</div>
PYTHON:
import cgi
form = cgi.FieldStorage()
# print HTTP/HTML header stuff
print """Content-type: text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head>
<title>Order Form</title>
</head><body>
"""
# print HTML body using form data
print "<h1>Kintoro Japanese Bar & Restaurant</h1>"
print "<h2>Customer Reciept</h2>"
print "<p>Customer Name:", form["custName"].value, "</p>"
print "<p>Customer Email Address:", form["custEmail"].value, "</p>"
print "<h2>Customer Address:</h2>"
print "<p>Street:", form["custAdd"].value, "</p>"
print "<p>City:", form["custCity"].value, "</p>"
print "<p>Province:", form["custProv"].value, "</p>"
print "<p>Postal Code:", form["custPostal"].value, "</p>"
Jack is correct, but there is a backstory and quick/dirty testing method for the future students.
Explanation first:
Originally, your KeyError said there was no Key with that name. After you've implicitly stated a key (the first part of a dict), it was then missing the Value for said key.
Dictionaries are a key-value pair, so both would need to be implicitly stated at the start of the script (in the scope the previous and following debugging-with-ease methods).
Slowing down the actions helps obtain clearer understanding;
Since this script is a fully loaded CGI that is told to start and finish by declaring variables for each key-value pair, you are seeing the end result of which - where python feeds text data to CGI, CGI then accepts and interprets said text, and gives some sort of response back to python (valid or not!), python can only give you the results of the results. Thusly, this error looks different than your standard (and excellent I may add) non-cgi / console error with followable tracebacks.
A quick/dirty test method:
Implicitly state an exact key-value pair before telling CGI to pass it back to python to use:
custName = { 'Name': 'John Smith' }
One would need to declare a default setting for each dict mentioned as values to have a fully operational loaded script ready to use, but the hint here is that custName would no longer present the error, but it would then complain about your next missing key-value pair.
Yeah, long answer and past classtime - I know. Hopefully, however, this will assist to understand the several parts of a 'single' issue than to solve it once for only a select few people.

HTML drop-down box with Google App Engine

I am creating a Google App Engine web application written in Python, and I would like to create a drop down box that displays different values corresponding to pages of a book that a user could choose from. I would like the action of the drop down box to be to direct the user to the page that corresponds to this link:
<a href='/viewpage/{{bookpage.key}}'>{{ bookpage.page }} </a>
The "bookpage" entity is passed to the html
Thank you!
David
Use a Jump Menu. Here is a pretty straight forward implementation.
Basically you'll just add a bit of JavaScript, and instead of writing an a tag, you'll write an option:
<option value='/viewpage/{{bookpage.key}}'>{{ bookpage.page }} </option>
What about <option value='/viewpage/{{bookpage.key.id}}'>{{bookpage.page}}</option>?
I hope it's not a dumb answer.
I'm not familiar with the google-app-engine but, the following javascript seems to do what you want. The python could generate the array variables on the server side, and then everything else would work properly.
I included the hardcoded arrays so you can see what is going on, but you can replace the arrays with the python code(assuming bookpage is some kind of dictionary):
i = 0
for bp in bookpage.keys():
print("mysites["+str(i)+"] = "+ bookpage[bp])+";"
print("sitenames["+str(i)+"] = "+sitenames[bp])+";"
i+=1
<html>
<body>
<script type="text/javascript">
var mysites= new Array();
mysites[0] = "http://www.google.com"; //Generate this line with python
mysites[1] = "http://www.bing.com"; //Generate this line with python
mysites[2] = "http://www.yahoo.com"; //Generate this line with python
var sitenames = new Array();
sitenames[0] = "Google"; //Generate this line with python
sitenames[1] = "Bing"; //Generate this line with python
sitenames[2] = "Yahoo"; //Generate this line with python
function changeLink(){
var index = document.getElementById("theselect").selectedIndex
document.getElementById("thelink").innerHTML=index;
var newlink = mysites[index];
var newstring = sitenames[index];
document.getElementById("thelink").href=newlink;
document.getElementById("thelink").innerHTML=sitenames[index];
}
</script>
<select id="theselect" onclick="changeLink()">
<option>Google</option>
<option>Bing</option>
<option>Yahoo</option>
</select>
<br />
<a id="thelink" href="http://www.google.com" > Google </a>
</body>
</html>
Clicking on the option box calls the changeLink() function, which then changes the link and the inner html of the tag.

Categories

Resources