Using PyQooxCard (PQC) as a GUI builder for qxtransformer
The PyQooxCard is a visual GUI builder base on the layoutEditor of the original
PythonCard package, extended by John Henry to support qxtransformer code generation. PythonCard is a visual toolkit package which is based on
wxwidgets/
wxpython. PQC allows you to create similar-looking GUIs for the desktop and the web - you can use the same resource files to create python executables and qxml templates. PQC is still under heavy development with
new feautures being developed, but we invite you to try it out and give us feedback...
Installation of prerequisites
Before installing PyQooxCard, you'll need to have the following packages installed and tested:
- Qooxdoo
- Qxtransformer
- Native version of Python (2.3, 2.4, or 2.5 will all work). It is not recommended to use the one that executes under cygwin if you're running on the Windows platform.
- Corresponding version of wxPython
Windows
Linux
Debian Etch, Ubuntu 8.04 (Hardy Heron)
- Fulfill the dependencies by apt-get install python-wxgtk2.6 if not already installed by default (Ubuntu)
Mac
OS 10.4 (Tiger) and 10.5 (Leopard)
Installation of PyQooxCard
- Download the modified PythonCard distribution from SVN using an SVN client of your choice from here:
https://www.qxtransformer.org/svn/qxtransformer/trunk/tools/PythonCard/
- Go
to the PythonCard folder and excute (with administrator rights) "python setup.py install" (Linux/Mac OS) or double-click on the setup.py file (if the file extension is connected with the right python executable). This
will install the necessary libraries in the site-packages folder matching you
platform and current python interpreter.
- Mac OS 10.5: /Library/Python/2.5/site-packages/PythonCard/
- Debian Etch: /usr/lib/python2.4/site-packages/PythonCard/
- Windows: \Python2.5\site-packages\PythonCard
- Go to to the tools/PyQooxCard folder and execute layoutEditor.py by double-clicking or on the command line. Two windows should show up.
The PQC editor in Windows
Hello World using PyQooxCard
To create your first PyQooxCard project, please follow these steps:
- Using standard qxtransformer steps, create a project with the name space helloworld. If you're a Windows user, you can skip this step. The project will be created for you automatically the first time you save your file in qxml format. Support may be added in the future to provide this feature for other platforms.
- Start up layouteditor.py as described above. We'll refer to the two windows above as the LHW (left-hand window), and the RHW (right-hand window).
- Select File and then New. Select one of the three types of menuing windows to create - there is no support for creating a Dialog window yet.
- From the LHW, click on Edit and select "Background Info". The ""Background Info" window pops up.
- Change the "Name Space" entry from "Template" to match the same name space used in step 1 exactly . Skip the rest of the entries for now and click OK.
- From the LHW, click on Component and select StaticText.
- From the RHW, check "vary" and then replace the "StaticText1" under Text to: "Hello World. This app was created in just a few minutes!".
- Change the name of this widget to HelloWorld.
- From the LHW, adjust the size and location of the StaticText so that it fits in the middle of the screen. For Windows users, if the layouteditor doesn't respond after some drag-n-drop or resize actions, it's because there is a long standing bug in layouteditor for losing its focus. All you need is to switch focus to another application (Alt-tab), and then switch back (another Alt-tab). In addition, you may see a lot of exception messages in the console window. You can safely ignore them.
- Create a Button and label it "Click Me!" using steps similar to the above steps.
- For the Button, enter an actionBindings exactly as follows (including the braces):
{"click":"Button1_click"}
At this point, your LHW should look like this:
- Save the file as helloworld.rsrc.py. For Windows cygwin user, the PyQooxdoo project directory, and the QxTransformer project directory must reside in the save drive (same drive letter). In addition, it's highly recommended that you do not use the name space directory created in step 1 as your PyQooxCard development directory for reasons below. Also, it's best if you use a development directory that is on the top of the directory structure - like c:\helloworld.dev. Doing so will enable PyQooxCard to create the qxtransformer project directories for you automatically.
- Don't exit the program just yet.
- You have just created a standard PythonCard project by the name of helloworld. The file helloworld.py looks like this:
helloworld.py
#!/usr/bin/python
"""
__version__ = "$Revision: 1.5 $"
__date__ = "$Date: 2004/04/30 16:26:12 $"
"""
from PythonCard import model
class MyBackground(model.Background):
def on_initialize(self, event):
# if you have any initialization
# including sizer setup, do it here
pass
if __name__ == '__main__':
app = model.Application(MyBackground)
app.MainLoop()
- Edit helloworld.py and insert the following Python code right before the "if __name__=='__main__':" line, and since Python is indentation sensitive, be sure to match the indentation level of the "def on_initialize" routine above:
Revised helloworld.py
#!/usr/bin/python
"""
__version__ = "$Revision: 1.5 $"
__date__ = "$Date: 2004/04/30 16:26:12 $"
"""
from PythonCard import model
class MyBackground(model.Background):
def on_initialize(self, event):
# if you have any initialization
# including sizer setup, do it here
pass
def on_Button1_mouseClick(self, event):
if self.components.HelloWorld.text=="Hello World. This app was created in just a few minutes!":
self.components.HelloWorld.text="No Python(almost)! Just click, click, click!"
else:
self.components.HelloWorld.text="Hello World. This app was created in just a few minutes!
if __name__ == '__main__':
app = model.Application(MyBackground)
app.MainLoop()
- Run the Python program helloworld.py. You should see how your program looks like from the desktop.
- From an external text editor, create a file containing the following Javascript segment and name it Button1_click.js (must be located in the same directory as helloworld.rsrc.py created in the step above.
Button1_click.js
if (HelloWorld.getText()=="Hello World. This app was created in just a few minutes!") {
HelloWorld.setText("No Javascript(almost)! No XML! No XSLT! Just click, click, click!");
}
else
{
HelloWorld.setText("Hello World. This app was created in just a few minutes!");
}
- From the LHW of the layouteditor, select File and then "Save as QXML...". If you follow the above steps in creating the qxtransformer project and use the name space properly, the default file name for the qxml file you are about to create should have been set to: /helloworld/frontend/source/xml/helloworld.Application.qxml. Don't change this name. For Windows users, if the qxtransformer project directory doesn't exist, it will be created for you automatically. Save the file and replace the default one created by qxtransformer as part of step 1 above.
- From the LHW, select File and then "Run QXT" to bring up the QxTransformer builder:
Notice that the location of your project makefile has been preselected base on the name space or home base setting of your Background Info. Click "Go" to transform this PyQooxCard desktop application into a QxTransformer/Qooxdoo web application.
- Click on "Browse Source" or use your browser of choice and open the file /helloworld/frontend/source/index.html.
Congratulations! You've just created your first web application - going from the desktop to the Web in just a few minutes!
There is an elaborate sample application by the name of qxsample in the
/PythonCard/tools/layoutEditor/QxSample directory. To try this sample, please follow the following steps:
- Create a standard qxtransformer project with a name space qxsample. As indicated above, if you're a Windows user, you can skip this step. The project will be
created for you automatically the first time you save your file in qxml
format. Support may be added in the future to provide this feature for
other platforms.
- Create a directory qxsample (must be a top directory) and copy the contents of the sample qxsample directory over there. Do not work in the qxsample directory provided.
- Startup layouteditor.py
- Select "File", "Open" and open the file qxsample.rsrc.py in the above mentioned sample directory
- Select "File" and then "Save as QXML..." to create the file /qxsample/frontend/source/xml/qxsample.Application.qxml. If you're a Windows user, you will be prompted for the creation of the qxtransformer project qxsample. Do that.
- Execute the "Run QXT" step as described above.
- Use your browser of choice and open the file /qxsample/frontend/source/index.html. For Windows users, you'll see a button on the bottom of the QXT screen to invoke the browser directly. It might work for other platforms as well.
The
sample program demonstrates the usage for all of the widgets that are supported using PyQooxCard. (Note that due to limitations imposed by Geocities' free service, you won't be seeing the full appearance of the sample program, and it might not be viewable at times if too many of you tried to view the sample).
Widgets Supported
Currently, there are no support for these PythonCard widgets:
BitmapCanvas, CodeEditor, Gauge, HtmlWindow, Notebook, and ToggleButton.
Likewise, there are no support for any Qooxdoo widgets that are not listed under the Component list of the layouteditor although you can accomplish that by using raw QxTransformer code and have the code added into your PyQooxCard project by using the actionBinding tags described below.
Widget Coordinates
Currently, PyQooxCard supports the use of absolute coordinates only. There is no direct support for layout widgets or sizers. The reason is that while PythonCard supports the use of wxPython sizers, they are somewhat incompatible with the layout managers in Qooxdoo. This will be an important development area in future versions of PyQooxCard.
In addition, your desktop applicaion will look slightly different when running under a browser. Be mindful of this and don't squeeze widgets too close to each other - especially when using default sizes.
The position values you see in the Background Info window of the layoutEditor is the present position of that window you are working on. By default, this will be the approximate starting position of your window within the browser. However, sometimes it might be desirable to specify a browser based position and use the desktop position to make it more convenient for working while inside the layoutEditor. For that, you would use the "run time position" data field. For instance, if the window is a sub-window within a static box, the "run time position" will be the position of the sub-window relative to the static box. For instance, a "run time position" of (0,0) for that sub-window would cause it to lined up with the upper left hand corner of that static box.
actionBinding Tags
With
any widgets (including the background window), the
tags listed in the actionBindings field is assumed to be the event
handlers of that tag. The content of the actionBindings is expected to
be a standard Python dictionary. For instance, an actionBindings entry
of:
{"click":"Button1_click","execute":"Button1_click",...}
indicates that the Javascript for the click and execute events can be found in the file
Button1_click.js.
Event Tags
Obviously the approach of handling event code in separate Javascript files will result in using lots of files and might create a maintenance issue. If you prefer to have all of the Javascripts for a particular window stored in one file, you can use the event actionBinding tag like:
{"event":("click","execute",...)}
When PyQooxCard encounters such tags, corresponding qxml code will be generated for qxtransformer to look for the eventlisteners such as
on_widgetname_click and
on_widgetname_execute from the file
namespace_events.xml, where namespace is the namespace setting of the window affected, and widgetname is the name of the widget for these eventlisteners. If this file does not exist, one will be created for you automatically. If the event listener in question does not exist within this file, code stubs will be created for you automatically. All you need to do is to fill in the actual action code desired. Note that when you perform a "Save as qxml" command, this event listener file will be automatically processed and copied over to the
\namespace\frontend\source\xml\includes directory for you. Do not copy this file manually.
Message Tags - Who's calling?
PyQooxCard supports Qooxdoo's message model via the actionBinding tag message like:
{'message': 'changeLabel'}
The widget dispatching the message does so by issuing a simple event actionBinding tag such as:
{'event': 'execute'}
As stated above, PyQooxCard will create a file
namespace_events.xml and places code stubs inside for handling these events and messages. A typical one might look like:
helloworld_events.xml
<qx:eventHandler name="on_button_execute">
// "this" refers to application,
// "widget" to the widget that this handler is attached to
// "event" is the event OR message object
qx.event.message.Bus.dispatch("changeLabel","Button clicked!");
</qx:eventHandler>
<qx:eventHandler name="on_text_changeLabel">
// "this" refers to application,
// "widget" to the widget that this handler is attached to
// "event" is the event OR message object
widget.setText(event.getData());
</qx:eventHandler>
<qx:eventHandler name="on_button2_execute">
// enter your event handler for widget 'button2', event 'execute' here
// "this" refers to application,
// "widget" to the widget that this handler is attached to,
// "event" is the event OR message object
qx.event.message.Bus.dispatch("changeLabel","Second Button clicked!");
</qx:eventHandler>
resourceEditor Property Editor
For easier editing, if you click on either the "actionBindings", "toolTip", or "userdata" field on the resourceEditor Property Editor, the following editing screen pops up:
Windows, windows, and more windows
While PyQooxCard only supports the creation of one window at a time, there are special actionBinding tags that can be used to manage child windows:
- {"insert":"qinc filename"}
- {"include":"qinc filename"}
or for multiple files:
- {"insert":("qinc filename1","qinc filename2","qinc filename3",...)}
- {"include":("qinc filename1","qinc filename2","qinc filename3",...)}
If you uncheck the "Visible at startup" flag from the Background Info window of a particular .rsrc.py file, PyQooxCard is going to assume that you're creating a sub-window or childwindow, and will create a qinc file accordingly. To do so, you must also specify the "Home Base" of this file - which is the name space used in creating the qxtransformer project of this entire application. For instance, if we are creating a sub-window by the name of child1 in the qxsample project, when you execute the "Save as QXML..." step, PyQooxCard will save the file to
/qxsample/frontend/source/xml/includes/child1.qinc.
The exact relationship between the main and other windows with the qinc file depends on how and where you specify it to be added using the actionBindings tags mentioned above. A
- An insert tag causes the qinc file to be inserted right before the </qx:widget> line of the corresponding widget in the qxml file. The window described in the respective qinc file becomes a child-window within that widget.
- An include tag causes the qinc file to be included right
after the </qx:widget> line of the corresponding widget in the qxml
file. The window described in the respective qinc file becomes a window that is independent with that widget. If the widget happens to be the main window, the qinc window in question becomes a pop-up window that can operate independent of that main window.
There are a number of other window attributes on the Background Info page that you can use to control the behavior of windows more precisely.
Don't change those qxml and qinc files
It is highly recommended that you do not make any changes directly to the qxml and qinc files created by PyQooxCard. These files are vulnerable and information stored within these files can get overwritten unintentionally when you're working with a PyQooxCard project. Through the judicious use of actionBindings tag files, you can safely store important program logics elsewhere.
If you're using Windows...
At the time of this writing, there appears to be a nasty problem somewhere within the qxtransformer -> qooxdoo process under Windows XP, believe to be caused by some part of cygwin, or may be an improper installation, or both. During either "make translate", "make source", or "make build", the process terminates with some unintelligible error message and you can no longer process your PyQooxCard project. When that happens, you can try one of the followings cures:
- Delete all of the files in the qooxdoo cache directory. For instance, that directory might be /qooxdoo-0.7.3-sdk/frontend/framework/.cache
- Recreate your qxtransformer project - be sure to save a copy of your xml directory (including the include sub-directory), resource directory, or any other data related directories. For this reason, as indicated above, it's best not to store any information in the qxtransformer project directory.
- If the problem persists (which it might - depending on what part of cygwin crashed), replace the entire qooxdoo-0.7.3-sdk directory
In addition, others have indicated that
increasing the amount of heap allocated to cygwin might help.
For most of you, this could be a non-issue and hopefully this issue has been resolved by the time you read this page. If so, smooth sailing with PyQooxCard - Bon Voyage!