[Repost from the old blog, don’t know if it works anymore]
Let us combine the greatness of HTML/CSS/Javascript for user interface with Python the best way to build backend to create a desktop app.
The basic idea is to use create a python webserver process, wait for it to start and display your app. After your app closes it will close the webserver process.
The code you can see and download below has a few extra features:
- Splash screen while python process starts
- Waits till webserver process returns a result so we really know it has started
- F5 – Refresh
- F11 – Fullscreen toggle
- F12 – Show Dev Tools
To make this work use the zip file at the bottom and put it in same folder as NWJS.
Only tested on windows with node-webkit 0.9.2(0.11.9)
A pretty standard node-webkit package file:
12345678910{"name": "wsgi","main": "app://whatever/start.html","window": {"width": 320,"height": 240,"toolbar": false,"fullscreen": false}}
package.json
The simple python WSGI app:
1234567891011121314151617181920212223from wsgiref.util import setup_testing_defaultsfrom wsgiref.simple_server import make_serverdef simple_app(environ, start_response):setup_testing_defaults(environ)status = '200 OK'headers = [('Content-type', 'text/html')]start_response(status, headers)yield "<h1>Python WSGI App</h1>"yield "<pre>"for key, value in environ.iteritems():yield "%s: %s\n" % (key, value)if __name__ == '__main__':port = 44408httpd = make_server('', port, simple_app)print "Serving on port "+str(port)+"..."httpd.serve_forever()
wsgi_app.py
Where the magic happens:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168<!DOCTYPE html>Starttype="text/javascript"var platform = require("os").platform;body {background: #272822;color: #FFF;font-family: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif;cursor: default;}Loading...We are using node.js document.write(process.version).platform: document.write(platform()).status: id="status"statustype="text/javascript"//************************************************************var pyexec = 'C:/Python27/python.exe';var basedir = '.'; //working dirvar pywsgi = basedir+'/wsgi_app.py';var startpage = 'http://127.0.0.1:44408/';var pagecheck = 'http://127.0.0.1:44408/404'; //no side-effect page to check if webserver is running//************************************************************var wsgi_process = null;var spawn = require("child_process").spawn;//------------------------------------------------------------function StartWSGI(){console.log('StartWSGI');if (platform() == 'win32'){pyexec = pyexec.replace('/','\\');pywsgi = pywsgi.replace('/','\\');basedir = basedir.replace('/','\\');}child = spawn(pyexec, [pywsgi,],{cwd:basedir});child.stdout.on("data", function(data) {return console.log("stdout:" + data);});child.stderr.on("data", function(data) {return console.log("ERROR: " + data);});child.on("exit", function(code) {return console.log("Encoding process exited with code: " + code);});console.log("StartWSGI_End");wsgi_process = child;function transferComplete(evt) {InitMainWindow();}function transferFailed(evt) {document.getElementById("status").textContent = "Waiting...";checkServer();}function reqListener () {document.getElementById("status").textContent = "Launching...";};function checkServer(){var oReq = new XMLHttpRequest();oReq.addEventListener("load", transferComplete, false);oReq.addEventListener("error", transferFailed, false);oReq.onload = reqListener;oReq.open("GET", pagecheck, true);oReq.send();}document.getElementById("status").textContent = "checking...";checkServer();}//------------------------------------------------------------function InitMainWindow(){var gui = require('nw.gui');// Get the current windowvar win = gui.Window.get();var new_win =gui.Window.open(startpage, {position: 'center',width: 640,height: 480,"toolbar": false,focus: true,show: false});// And listen to new window's focus eventnew_win.on('focus', function() {console.log('New window is focused-b');});// Release the 'win' object here after the new window is closed.new_win.on('closed', function() {console.log("mainclose");wsgi_process.kill();win.close();win = null;});new_win.on('loaded', function() {console.log('New window is loaded');win.hide();new_win.show();new_win.focus();var awin = gui.Window.get(this);awin = this.window;awin.onkeyup = function(e) {//console.log(e);if (e.keyIdentifier == "F5"){new_win.reload();}if (e.keyIdentifier == "F11"){new_win.toggleFullscreen();}if (e.keyIdentifier == "F12"){if (new_win.isDevToolsOpen()){new_win.closeDevTools();}else{new_win.showDevTools();}}};});}//======================================================================var gui = require('nw.gui');var win = gui.Window.get();win.on('loaded', function() {console.log('New window is loaded');StartWSGI();});//======================================================================
start.html