|Home | Tutorial | Classes | Functions | Qt Scripter | Language | Library | Qt API | QSA Articles | Qt Script for Applications | ![]() |
It is a common approach in software development to separate different functionallity into different software components. In this article we try to describ how a scripting language with good C++ bindings can increase the flexibitly and reuse value of individual software components.
The sourcecode and examples used in this artical are downloadable from here.
The application used in this article contains a set of image processing software components, which we will for simplicity call a module. We have a module for loading an image and another for displaying the image on screen. In addition we have some modules to do the processing in between.
What we wish to show with this application is how QSA can be used to script enable software components in such a way that it increases the overall flexibility with a minimum amount of programming effort. This gain comes from using already existing code and simply glue it together using QSA.
We will now go throught how the modules in the application work and how they can be used from QSA. For the sake of reference, lets start with a simple example
var loader = new ImageSource; var display = new Renderer; connect( loader, "output(Data)", display, "input(Data)" ); loader.file = "myimage.png"; loader.load();
What happens in this script is that we create two modules, the ImageSource and the Renderer. The output of the ImageSource is connected to the input of the Renderer which is used to display images. We then set the filename for the ImageSource start processing by calling the function load() in the ImageSource. The ImageSource will then load the image and give the image to the renderer which displays it.
The ImageSource class in example above is really a C++ class that has been made available from script using functionallity in QSA. For this to work, the C++ class has be derived from QObject. When this requirement is met all the class' slots and properties are automatically accessible from the scripting language. Also, to be able to instantiate the class from script we also need to implement a subclass of QSObjectFactory that will, on demand from QSA, create the module. The implementation of the module factory can be found in: modulefactory.h and modulefactory.cpp.
Whan a module receives input, it will process that input and send the produced output to all other modules connected to that slot. It is important to realise that only the setting up of processing chains and configuration of modules are done in the script. The real number crunching is done in C++ which means that the execution speed is limited only by the efficiency of the C++ implementation, while still obtaining the flexibility that a scripting language offers.
A list of the modules implemented in the example and a short description of them follows below. The implementation of the modules can be viewed in modules.h and modules.cpp
The application that has been written around the modules example is rather trivial and will not be discussed in detail in this article. We will just sum up its functionallity and show some examples.
As can be seen from the image below the application has a script editor and a list of script functions. The script in the editor is parsed at regular intervals so that the list is always kept in sync. It is worth noting that the editor is an object of the QSEditor class that has been embedded in the application. This gives, with minimal effort, access to code formatting, syntax highlighting and code completion.
Below is one of the sample scripts available in the distribution. It uses all the available modules. To the left of the code is shown the original image (top) and the processed image (bottom). The example sets up the processing to first load the image. The image is then sent into the Threshold module which creates the steps in the resulting image. The thresholded image is then sent to the Smudger module where the edges are smoothed out a bit, causing a more gliding transition between the steps in the image. The next step is the BumpMapper module where the light source is positioned in the upper left region of the image causing this area to luminous while shadows are cast on the other side. Finally the image reaches the renderer which opens up a window displaying the resulting image.
function doAll() { var ren = new Renderer(); var src = new ImageSource(); var bump = new BumpMapper(); var thres = new Threshold(); var blur = new Smudger(); connect( src, 'output(Data)', thres.input ); connect( thres, 'output(Data)', blur.input ); connect( blur, 'output(Data)', bump.input ); connect( bump, 'output(Data)', ren.input ); src.file = 'bump.jpg'; thres.steps = 10; bump.smoothness = 4; bump.light = new Point( 150, 150 ); bump.radius = 250; blur.iterations = 4; src.load(); } |
![]() |
For fun, try change some of the modules properties or take some of them out to see what happens when you run the example again.
At this point one might be thinking that this is no different than the same code written in C++ using the components directly. This is true if one want to recompile for every small change one does, that is, if you have access to a compiler at all.
It would also be possible to provide the same level of functionallity in a graphical application. One could write a configuration dialog for each module and write some widget for doing the connections graphically. Such a GUI takes time to write, and will most likely be task specific. Scripting the same functionallity can be done directly with only a minimal amount of programming, if any at all. And the scripting language is not bound to any given task and is therefore completly generic. There are also some features that are more difficult to reflect in a GUI, such as iterations and conditional execution. These are easily available in a scripting language, but are not trivial to represent in a graphical application.
Another common usage area of application scripting is the on-the-fly customization of existing functionallity, in which case one does not wish to spend time programming user interfaces, but rather hook together the pieces you want with a few scripting statements and let it run. For this purpose scripting is ideal.
We have now showed how wrapping C++ functionallity in QSA increases the flexibility and usability of existing code. We make use of the QSObjectFactory to enable use of C++ classes from script and we use the QSEditor to simplify the editing of script files in the application. All in all it shows how QSA can improve the functionallity of existsing application code.
Copyright © 2001-2003 Trolltech | Trademarks | QSA version 1.0.0-beta2
|