Summary
Combine the power of Python with the polish of Flash to create a desktop application. This approach will also work with any language that has support for creating an XML-RPC server (Java, Ruby, C++, to name a few). Also, The XML-RPC server can easily be on another machine.
Advertisement
I have been a Python enthusiast for over 10 years. Its power and expressiveness has made it my first choice when solving my own programming problems.
However, whenever I've wanted to create a program with a user interface -- an end-user application, for example -- I've had problems. There have always been too many choices for Python GUI libraries, and each one has its own idiosyncrasies. I've studied most of them to one degree or another and over time WxPython (based on WxWindows) seems to keep pulling in front of the pack, but in my own experience I've found it far from the ideal solution. Mostly it seems like too much work, which is true for most of the Python GUI libraries.
The more I work with it, the more I find Flex to be preferable to any other GUI solution that I've explored. As I learn more about Actionscript, I gain greater appreciation for all the effort invested by the designers of that language to make life easy for the programmer. The combination of MXML and Actionscript is amazingly well-balanced; MXML keeps you at the "big picture" level most of the time, and you can easily drop down into Actionscript to gain detailed control. Flex was designed with user interfaces at the forefront, so it includes true properties and events as well as "data binding" to automatically move data from one place to another when something changes. It's unfortunate features like this never made it into Java.
And then there's Flexbuilder. Built atop Eclipse, this provides an incredibly powerful development environment with autocompletion, integrated help, debugging, and more. I haven't seen support for any of the Python GUI libraries that even comes close.
Creating Python XML-RPC Services
There are numerous RPC solutions which allow you to cross between one language and another, but I've had the most experience -- and the most satisfying experiences -- using XML-RPC. So far it's solved all the problems that I've encountered, and it's simple to understand and straightforward to use. And it's an excellent solution for distributed systems, since you can effortlessly cross over machine boundaries (you do, however, need to come up with your own callback approach when starting long-running processes on remote machines).
Python has the philosophy of "batteries included," which means that there's a very good chance that whatever you need is part of the standard library. This isn't just convenient; the standard libraries tend to get much greater focus and support than open-source projects, so the quality of the code tends to be better.
The SimpleXMLRPCServer library allows you to easily create a server. Here's about the simplest server you can create, which provides two services to manipulate strings:
import sys
from random import shuffle
from SimpleXMLRPCServer import SimpleXMLRPCServer
class MyFuncs:
def reverse(self, str) :
x = list(str);
x.reverse();
return ''.join(x);
def scramble(self, str):
x = list(str);
shuffle(x);
return ''.join(x);
server = SimpleXMLRPCServer(("localhost", 8000))
server.register_instance(MyFuncs())
server.serve_forever()
You can publish regular functions (not associated with a class), but I find the class approach is cleaner. This particular server is located on the current machine at port 8000, and that's all the client needs to know.
Once the server is started, we need to make a client that will connect to the server and call the services. This is also very easy to do with Python using the standard ServerProxy class in the xmlrpclib library:
from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost:8000")
print server.reverse('giraffe')
print server.scramble('giraffe')
Once you make a connection to the server, that server acts like a local object. You call the server's methods just like they're ordinary methods of that object.
This is about as clean an RPC implementation as you can hope for (and other Python RPC libraries exist; for example, CORBA clients). But it's all text based; not very satisfying when trying to create polished applications with nice GUIs. What we'd like is the best of all worlds -- Python (or your favorite language) doing the heavy lifting under the covers, and Flex creating the user experience.
Calling XML-RPC Services from Flex/Apollo
One thing I've found a little puzzling about Flex is the decision about which libraries are included in the standard distribution. For example, in earlier versions there was an MP3 player component, but for some reason this has vanished (even thought the Flash player itself directly supports MP3). And I personally like XML-RPC a lot, so it would seem logical (to me) to include that as well. Fortunately, other people have written replacements, and the Flex packaging mechanism makes these easy to incorporate into your own projects.
After hunting around, I found an Actionscript XML-RPC client library, along with a description and an example, here. It was written by "Akeem"; I basically worked from his code but I trimmed it down to make it easier to read.
To use the library, download it and unpack it somewhere. The package includes all the source code and the compiled as3-rpclib.swc library -- the .swc extension indicates an archive file, and pieces of this library can be pulled out and incorporated into your final .swf. To include the library in your project, you must tell Flexbuilder (you can get a free trial or just use the free command-line tools, and add on the Apollo portion) where the library is located by going to Project|Properties and selecting "Apollo Build Path," then choosing the "Library path" tab and pressing the "Add SWC..." button. Next, you add the namespace ak33m to your project as seen in the code below, and you're ready to create an XMLRPCObject.
Note: the only reason I used Apollo here was that I was thinking in terms of desktop applications with nice UIs. You can just as easily make it a Flex app.
Here's the entire Apollo application as a single MXML file, which I'll explain in detail:
MXML is a higher-level abstraction of an application than is Actionscript, but the compiler translates MXML into Actionscript, and you can choose to write your entire application in Actionscript instead (if you want to do a lot of extra work -- you don't gain anything from it).
An MXML file is proper XML, so it begins with the standard XML tag. The body begins with a tag that determines whether it is a Flex or Apollo application, followed by XML namespaces. The first namespace is the standard mx that you'll see in every application, but the second ak33m is the special one added to use Akeem's XMLRPCObject. This is a good example of how to incorporate an external library (you can also just place the source file in your project directory).
The focus of MXML is organizing and laying out components. Note that the main body tag includes a layout attribute; "absolute" means that the components will be glued to their positions regardless of the size or proportion of the application.
MXML provides support for form creation via various Form... tags; it's possible to create these more verbosely, but notice that using the Form... tags requires less work than it would in HTML (there are also helpful fancy components like calendar date choosers, and a number of standard validators which automatically check user input). The fact that the result will look the same under every browser on every platform, without any extra effort, makes creating forms this way very appealing.
Each FormItem can have a label, and it neatly organizes the label with the item (something that would take a table in HTML). The TextInput component allows the user to enter text, while the Text component is for display. I'm just showing you the very basic use of these components; they can do a lot more.
Every component can be given an id so it can be referenced elsewhere in the program; it's like a variable name for that instance of a component. In this program I only give ids to components that I actually reference.
Each component supports a set of events, and you can attach functionality to an event. In the cast of the TextInput, the change event (fired when the text in the input box is changed in any way) calls the manipulate() method, defined at the bottom of the program.
The XMLRPCObject, in this case, only needs an id and the "endpoint" to tell it where the server is.
A Script object is wrapped in CDATA because it may contain special characters that need to be escaped. Here, you see Actionscript code embedded directly into the MXML file, but it could also have been placed in an external .as file and referenced from within the MXML.
One of the first things you'll notice about Actionscript, as a Java programmer, is how remarkably similar it is to Java. Many of the basic concepts and even keywords are the same, which makes it relatively easy for a Java programmer to learn. However, Actionscript often makes things a lot easier than Java does -- for example, while packaging and import statements are very similar, you are not faced with the nightmares of Java's CLASSPATH.
Some things are different. As you can see, it's possible to have free-standing functions. And when you define a function, you must actually use the function keyword (Actionscript is actually a superset of Javascript). Type declarations are optional (although Flexbuilder issues warnings, and I like my warnings to be useful so I add the necessary syntax); without them you get dynamic typing. Type declarations are expressed after type identifiers or function argument lists, following a colon.
Note the manipulate() function, which takes no arguments and returns void. Remember we set up the TextInput instring to call manipulate() whenever the input text is changed. When this method is called, it uses the server XMLRPCObject to call both the methods available on the server. At first glance, it looks similar to the Python client.
However, the Python client was making synchronous calls -- it waited for the XML-RPC server to return the result before continuing. Flex is set up for asynchronicity, which means that it can initiate a call and continue processing while that call runs. The problem with asynchronicity is that you need to somehow catch the result, and the solution is to install a callback function which will automatically be called when the result comes back. Flex comes with builtin support for installing asynchronous callbacks, as you can see from the import statements.
The callbacks are attached as ItemResponders to the object returned from the XML-RPC call, using the addResponder() method. The first argument of the ItemResponder constructor is the function to be called upon success, the second argument is the function to be called in the event of failure. For both calls we are only interested in the first argument that comes back, which contains the result value from the XML-RPC call (from the code, you can see that it's possible to construct more complex callbacks). All the "success" methods do is insert the results in the appropriate text fields.
Performance
Flash 9 includes a new, high-speed JIT compiler which has a very large impact on application performance -- some have suggested as much as 10x. The UI portion of your application is thus unlikely to be a bottleneck; it's more probable that the underlying Python program (in this case) or even the XML-RPC calls might cause slowdown, although you'll find that making local XML-RPC calls tends to be remarkably fast.
One of the benefits of this approach is that the UI is not only fast, it's completely separated from the implementation of the underlying program logic, which makes it easier to apply performance improvements. In Python 2.5, for example, the new ctypes library makes it very easy and fast to call DLLs written in another language, so spot performance tuning becomes quite easy. If more dramatic measures become necessary, the approach used in this article allows you can swap out the underlying application without changing the UI. In any event, remember that UI events are rarely the bottleneck in a program's performance, and even if you do run into issues -- dealing with graphics, for example -- Flash is designed to optimize this kind of performance.
For me, the promise of this approach is in programmer productivity. You can write the underlying program logic in using the most productive language for the job, and produce the UI with a system (Flex) that's optimized for that purpose.
Resources
I'm currently reading Rich Internet Applications with Adobe Flex and Java by Fain, Rsputnis and Tartakovsky, and Programming Flex 2 by Kazoun and Lott, although there are lots of other books out there on Flex and Actionscript.
Watch my calendar for upcoming Flex/Apollo events as well as the Rich Internet Application Summit.
Actually, I've learned to use quite a number of GUI toolkits. I just haven't been particularly satisfied with any of them. The other thing is that I tend to use different languages to solve different problems, and "one GUI system to bind them all" is very appealing.
Plus I've used XML-RPC a fair amount for distributed systems, and putting a cross-platform GUI (especially one with a transparent install process) on top of such systems is very helpful.
It sounds good. I learned Python based on your recommendation and am in the process of learning Flex. After going through the Python learning curve, I wish I could stay in it for the UI. Jython opens up the Java libraries to Python programmers. Have you heard anything about Python on Flex? Sort of a Flython port?
Have you given any consideration to expanding this example into a more complete demonstration of the Model-View-Controller technique?
I'd be especially interested in using Python to implement the Model and Flex/Apollo to implement the View and Controller necessary for a simple outliner or hierarchical editor.
Continuing on my earlier post on Flex/Java books, I'm looking for books that don't mandate the Flex Dataservices stuff (which has some ridiculous pricing schemes).
Hello, I too have been on the Apollo/AIR bandwagon as of late. I've looked at a lot of UI toolkits in the past and they've all left me feeling a bit dirty, compared to a lot of the web development and MSFT client development I've done in the past. (I've looked at wxPython, QT and XUL. I've heard that Java Swing is pretty good these days, though, I haven't looked at that in years.) I was really looking forward to the potential with MSFT's Silverlight combined with the DLR and IronPython for potentially building cross-platform apps with a rich MSFT UI. But -- the last I checked -- it looked like Silverlight was only for web browsers. Plus, Adobe seems to have a better reputation for creating cross-platform software (never heard any complaints about Photoshop being sub-par on wither Windows or OSX). Then I found Adobe Apollo. I'm not going to say it's the end all or be all, but it does make make building cross-platform rich appplications simple and elegant. There's a huge community around offering extra visual components. While, I'd prefer to be able to work in Python, Actionscript 3.0 isn't that bad. It's pretty dynamic. If you have any bit of Java background, especially in Eclipse, you'll pick it up in a few minutes. And, if you've ever programmed in ASP.NET, or WPF, then the MXML will be really simple to learn. It's amazing how similar the MXML and ASP.NET object models function. Now my questions for anyone here. SimpleXMLRPCServer seems quite cute, but what about building endpoints for a production ready system? I'd like to figure out how to architect something a bit stronger? Does anyone know of any RESTful Python APIs that combine easily with something like SQLAlchemy for producing a controlled server endpoint, maybe with Apache or something? (I've seen a lot of Ruby articles on how simple it is to add RESTful support to their Models). Should I be looking at something like Django or TurboGears? Just trying to get my bearings around this before I research further. Thanks.
Since 2 years, I use a similar solution : a XML-RPC / JSON / RDF server by using the Python library CherryPy and the framework XulRunner for the UI. XulRunner use XML like Flex but is truly cross-platform (Windows 98 +, Mac OS-X 10.2.8 +, Linux 2.4 +) but Adobe AIR needs recents systems (Windows XP SP2 + or Mac OS-X 10.4.8 +) and there is no runtime for Linux today. XulRunner can access filesystem like AIR, and also can be easily extended by using others languages like C++ ou Python.
> Now my questions for anyone here. SimpleXMLRPCServer > er seems quite cute, but what about building endpoints for > a production ready system? I'd like to figure out how to > architect something a bit stronger? Does anyone know of > any RESTful Python APIs that combine easily with something > like SQLAlchemy for producing a controlled server > endpoint, maybe with Apache or something? (I've seen a > lot of Ruby articles on how simple it is to add RESTful > support to their Models). Should I be looking at > something like Django or TurboGears? Just trying to get > my bearings around this before I research further. Thanks.