Skip to content

Commit

Permalink
Merge pull request #84 from enthought/jigna-docs
Browse files Browse the repository at this point in the history
Docs and example cleanup
  • Loading branch information
prabhuramachandran committed Mar 22, 2017
2 parents 955d075 + 60fdc1e commit 8d86ef5
Show file tree
Hide file tree
Showing 33 changed files with 59 additions and 95 deletions.
138 changes: 51 additions & 87 deletions docs/source/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,30 @@ widget or over the web in a browser.


Installation
-------------
============

Jigna currently only works with Python-2.x, 3.x is not yet supported. You will
require the following packages installed:
Jigna works with Python 2.x and Python 3.x (although for 3.x, you have to install
the dependencies yourself).

* You will need to have Traits_ installed to use Jigna.
The setup procedure is simple. Make sure you have a Python installation to
which you have write access and run the following command:

* Jigna can be used either as part of a Qt application or can be used to
display a user interface on a web browser. If you are only interested in
using Jigna in a Qt-based application, you will also require pyface_.
..code:: bash

* If you need to use the web backend, you will require Tornado_.


.. _Traits: https://github.com/enthought/traits
.. _pyface: https://github.com/enthought/pyface
.. _Tornado: http://www.tornadoweb.org/en/stable/


Installation itself is standard and can be done from source via either::

$ python setup.py install # or
$ python setup.py develop
source ./develop.sh

The primary use of jigna is to provide a way to write desktop GUI applications
using HTML, and we use the Qt backend for that. You can also use jigna to write
GUIs that run on the browser. This is done via the web backend.

Examples
---------
========

There are several examples to get started, look in the ``examples/`` directory
and run them.

Tests
------
=====

Running the tests requires selenium_ and nose_. The tests are in
``jigna/tests/``. You may run them from the root directory of the sources
Expand All @@ -54,47 +45,48 @@ using ``nosetests``.
.. _nose: https://pypi.python.org/pypi/nose


Getting started
----------------
Getting Started
===============

Let us say we have a nice model written in Python (specifically, in Traits_)::
Let us say we have a nice application model written in Python (specifically,
in Traits_)::

from traits.api import HasTraits, Str

class Model(HasTraits):
class Person(HasTraits):
name = Str
greeting = Str
def _name_changed(self):
self.greeting = "Hello " + self.name

model = Model(name='Fred')
person = Person(name='Fred')

We would like to write simple HTML to visualize this and have the model and
view be fully connected. Here is a sample HTML (an AngularJS_ template)::
Jigna lets you visualize this model using HTML such that the model and the
view are fully connected. Here is a sample HTML (an AngularJS_ template)::

body_html = """
Name: <input ng-model="model.name"/><br>
Name: <input ng-model="person.name"/><br>
Greeting:
<h1>{{model.greeting}}</h1>
<h1>{{person.greeting}}</h1>
"""

Notice how the HTML is directly referencing model attributes via model.name
and model.greeting. We now bind this declarative view to the model and create
Notice how the HTML is directly referencing model attributes via person.name
and person.greeting. We now bind this declarative view to the model and create
a Qt based UI::

from jigna.api import View
person_view = View(body_html=body_html)
from jigna.api import HTMLWidget, Template
template = Template(body_html=body_html)

from PySide import QtGui
app = QtGui.QApplication([])
person_view.show(model=model)
widget = HTMLWidget(template=template, context={'person': person})
widget.show()
app.exec_()

This produces an HTML UI which responds automatically to any changes in the
model and vice-versa. It can optionally be styled with CSS and made
interactive with Javascript. Clearly the above example is a toy example, but
this shows a nice way of easily building rich, live user interfaces for Python
apps.
This produces a Qt window containing an HTML UI which responds automatically
to any changes in the model and vice-versa. It can optionally be styled with
CSS and made interactive with Javascript. This provides a nice way of easily
building rich, live user interfaces for Python apps.

This is nice for several reasons:

Expand All @@ -115,55 +107,27 @@ This is nice for several reasons:
* There is a complete separation of view from the model and this allows us to
hand off the entire UI to an HTML/CSS/JS guru.

And if this were not enough, the view can also be easily served on a web
browser if we just did the following::
And since this is HTML, the jigna ``Template`` can also be easily served
on a web browser if you don't have Qt installed. The wiring changes a bit for
this, so the final example looks like this::

person_view.serve(model=model)
from tornado.ioloop import IOLoop
from jigna.api import WebApp

ioloop = IOLoop.instance()

app = WebApp(template=template, context={'person': person})
app.listen(8000)

# Serving the app on http://localhost:8000/.
ioloop.start()

This starts up a web server to which one can connect multiple browsers to see
and interact with the model.

.. _AngularJS: http://angularjs.org/


How is this different from just HTML rendered via webkit?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For a simple Python desktop application, it is relatively easy to create an
HTML view using a webkit browser widget. However, the connection between the
model and the HTML UI can be involved resulting in fairly complicated code.
Most web frameworks provide this functionality but are web-centric, and are
centered around building web applications, not desktop applications.

Our goal is to be able to build a desktop UI completely in HTML where the HTML
template always remains live by referring directly to Python object attributes
and methods. Changes in the Python side should update the UI and user inputs
on the UI should be able to update the model. Also, we need to have clear
separation between the view and the model. Jigna provides us this capability.


How it works
~~~~~~~~~~~~~

It turns out that Qt's ``QtWebkit`` browser has support for in-process
communication between its Javascript engine and the running Python
application. We use this communication channel to create a Javascript proxy
for Python models.

The other nice piece in this story is AngularJS, which provides good
model-view separation between its HTML template and the corresponding
Javascript model. AngularJS has great support for two-way data binding between
the template and the model, which keeps the template expressions always in
sync with the JS model. This makes sure that the HTML you need to write is
terse and simple.

We combine these two pieces to create a lazy-loaded Python-JS bridge which
provides us the two-way data binding between the Python model and the HTML
view. We use Traits to write models in Python. Traits lets us define
attributes of an object statically, and supports notifications when the
attributes change. Jigna integrates well with traits so that these
notifications automatically update the UI. Similarly, user inputs on the UI
change model attributes, call public methods on the model as well. Note
however that you don’t need traits and you can bind it to your plain old
Python objects as well - you would just need to add your own events if you
want your models to be updated outside of the UI.
The above example was very simple as the purpose of that was to show how
jigna is wired together. For further use cases of jigna, please refer to the
examples in the ``examples`` directory. They are numbered and are meant to act
as a tutorial if followed in sequence.

.. _AngularJS: http://angularjs.org/
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion examples/templating.js → examples/ex16_templating.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ app.run(function(){
app.directive('personView', function(){
return {
scope: {person: '='},
templateUrl: 'template_person.html'
templateUrl: 'ex16_template_person.html'
}
})
2 changes: 1 addition & 1 deletion examples/templating.py → examples/ex16_templating.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Person(HasTraits):
<html ng-app='templating'>
<head>
<script type='text/javascript' src='/jigna/jigna.js'></script>
<script type='text/javascript' src='templating.js'></script>
<script type='text/javascript' src='ex16_templating.js'></script>
</head>
<body>
<person-view person="fred"></person-view>
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def reset(self):

#### UI layer ####

template = Template(html_file='custom_angular_application.html')
template = Template(html_file='ex17_custom_angular_application.html')

#### Entry point ####

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def _update_mesh_data(self):

#### UI layer ####

template = Template(html_file='mayavi_webgl_demo.html')
template = Template(html_file='ex20_mayavi_webgl_demo.html')

#### Entry point ####

Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions examples/vuejs_demo.py → examples/ex22_vuejs_demo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
This example shows how to initialize Jigna's HTML interface by reading
a full html file, rather than specifying body_html and head_html.
This example shows how to use Jigna using the Vue.js Javascript framework,
instead of AngularJS.
"""

#### Imports ####
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def update_name(self, name):

#### UI layer ####

template = Template(html_file='simple_view_full.html')
template = Template(html_file='ex2_simple_view_full.html')

#### Entry point ####

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Person(HasTraits):

# The base_url field specifies where to look when trying to get external
# resources(defaults to an empty string, i.e. the current directory)
template = Template(body_html=body_html, base_url='user_resources_data/',
template = Template(body_html=body_html, base_url='ex5_data/',
recommended_size=(600, 600)
)

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 8d86ef5

Please sign in to comment.