[ Lit Window Library at SourceForge[ Lit Window Productions Homepage ]  [ wxWidgets Tips&Tricks ]  [  wxVisualSetup ]

Main Page | Modules | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages


RapidUI questions

Table of contents

Q. What is RapidUI?
Q. Will rapidUI be able to handle complex real-world scenarios?
Q. What is the performance overhead I have to pay for using rapidUI?
Q. Do I have to use special data types such as CVariant to be able to use rapidUI?
Q. Can I use my own data types with rapidUI?
Q. Can I use rapidUI with third party objects?
Q. What is the difference betweeen RapidUI and Data Binding?
Q. What does the code look like? Can you give me an example?
Q. Hm, this looks very complicated. How can this be faster than traditional coding?
Q. Can you give a longer example?
Q. I could simply buy a third party UI control (ActiveX control, plugin, whatever) that does what I want to. Why should I bother with RapidUI?
Q. I can use rules to describe 99% of my User Interface, but I still need a very special algorithm for the last 1%. Can RapidUI cope with that?
Q. Will RapidUI work with other GUI Frameworks besides wxWidgets? What about Qt? MFC?
Q. What license will the "Lit Window Library" be released under?
Q. I have some suggestions and/or more questions. How can I contact you?
Q. I want to contribute. How can I help?
Q. Who is behind "Lit Window Productions"? Who are you?
-- end table of contents --

Q. What is RapidUI?

RapidUI is the working title for an effort to speed up production quality UI development by a factor of 10. I put emphasis on the 'production quality' to set it apart from application generators and other tools that allow you to create a quick prototype. With them you throw together a couple of controls, put in a little code and create a good mock for demo purposes or as a basis for later work. RapidUI is different. It is a library of objects that make developing a user interface much easier.

Traditional UI coding

Properties, methods and events...
If you have ever worked with Visual Basic, Delphi or .NET you will have come across the traditional programming paradigm: properties, methods and events. Properties resemble members of a class, methods are - of course - member or global functions. These two items are natively supported by most programming languages. Widespread use of events started when graphical user interfaces gained popularity in the late 1980ies, early 1990s. Programming for an event loop or message loop required different programming techniques than the strictly sequential programming everyone used before. Events are beginning to be supported natively by some programming languages, namely C# and VB and Microsofts Extension to C++. There are also good class libraries such as Boost or Qt that provide a programmer with C++ objects that make handling events a lot easier.
...and a lot of code to wire them together.
But to write a user interface, you still have to write a lot of code to 'wire everything together'. That is where most the work has to be done and its also the part that is most difficult to maintain, especially as your user interface gets larger.
Wiring it together...
With 'wiring together' I mean
All the stuff that needs to be done to code the behaviour and interactions of the properties, methods and events.

RapidUI coding

Properties, Methods, Events and Rules...
RapidUI adds rules to the 'properties, methods, events' paradigm. If you think about it, you can describe most of the behaviour in simple rules. Here are a few examples:
Rules that are always true.
It is very easy to describe the required behaviour in rules, but difficult to implement and enforce the rules with the traditional sequential programming paradigm. That is where RapidUI helps you. Once you write down the rules, the rapidUI mechanism will take over and ensure that the rules always evaluate to true. It tracks changes to the variables and controls and reevaluates those rules that are affected by the changes, propagating changes to dependent rules if neccessary. In simpler words:
write the rules and forget about them...
This is how rapidUI aims to reduce the work.

Library of UI behaviour

This last point is especially important. Currently you have to rewrite the 'wiring' between controls everytime you create a new UI, even if the behaviour is almost identical except for the data type. How many times have you written the 'Add/Modify/Delete' UI requirement, letting the user select a record from a list, display the record in a form, letting the user modify the values, saving the changes, letting the user add a new record, letting the user delete a record?
RapidUI rule libraries are truly independent of the objects they work with. With RapidUI it will be possible to identify frequent UI scenarios and put them in a library. Then, when you have to create a UI you simply reuse the rules and save a lot of time. Such a library of rules can do for UI programming what the STL and similar libraries do for writing code. It could contain rules for:
in short, it could contain many elements you currently have to rewrite again and again.

Q. Will rapidUI be able to handle complex real-world scenarios?

C++ allows very complex expressions and scenarios. I am afraid that rapidUI is a nice idea, but won't be able to handle real-world complexity.
  1. rapidUI rules allow almost the same complexity as C++ expressions. If you use C++, you can use C++ expressions as rules and the compiler will generate almost the same code as it would for hand-crafted UI code.
  2. The success or failure of rapidUI will greatly be affected by the 'transition points', where the traditional programming practice meets the rapidUI method. The rapidUI design aims at a very smooth transition between the two worlds. The overhead required by rapidUI will be kept to an absolute minimum.
Here is a rule written in C++ that enables control "w_someControl" only if a checkbox is unchecked and the selection index of a list box equals 2.
rule<bool>( wnd("w_someControl.Enable"), ! wnd<bool>("w_checkbox.Checked") && (wnd<int>("w_listbox.Selection") == 2) )
The same rule written in plain text and parsed by the rapidUI expression parser:
bool: w_someControl.Enable= ! w_checkbox.Checked && (w_listbox.Selection:int == 2)

Q. I can use rules to describe 99% of my User Interface, but I still need a very special algorithm for the last 1%. Can RapidUI cope with that?

Yes. This requires what I call a 'transition point' between traditional (sequential) programming and rapidUI. The rapidUI mechanism allows the control flow to seamlessly leave rule based coding, execute code of your own and reenter the rule based world. You can mix and match rules and methods/properties/events and use the best of both worlds simultaneously.

Q. What is the performance overhead I have to pay for using rapidUI?

In real-world scenarios the performance overhead should be neglible. In some situations the rapidUI may actually perform faster than an OnIdle based scheme. OnIdle calls are evaluated everytime the UI becomes idle. This can consume considerable resources, especially when the user interface consists of several hundred controls. rapidUI on the other hand only evaluates those properties, rules and controls that have actually changed or depend on a value that has changed.

Q. Do I have to use special data types such as CVariant to be able to use rapidUI?

Q. Can I use my own data types with rapidUI?

You do not have to use special data types such as Variant. RapidUI is able to work with any data type you define. All that is required is that you create a data adapter for your data type. Data adapters are a kind of extended runtime information (reflection, if you prefer Java speak). The litwindow data adapter mechanism usually takes only a few lines of code and is very easy to implement.
Suppose you have defined a struct
struct SomeStruct {
    bool    m_autoSave;
    string  m_userName;
To create a data adapter for this struct, include the following lines in one of your source (not header) files.
Data adapters have already been implemented and work very well. The example above is a working real-world example. These four lines are really all that is needed.
If you have used extended runtime information mechanism before you might notice that the macros above do not include any type information. The litwindow data adapter mechanism is especially easy to use because it is unneccessary to duplicate the type information that is already present in the class/struct declaration. The four lines are really all that is needed.
C++ templates are at work behind the scenes to automatically determine the type of the member elements. This works in almost all situations except when Get/Set functions are involved.

Q. Can I use rapidUI with third party objects?

Yes. One of the strengths of the data adapter mechanism is that you don't have to modify the class declaration to be able to use data adapters. A data adapter is simply a wrapper around an existing class interface and is strictly add-on.
Suppose you want to use the wxDateTime class, a class handling date and time, with rapidUI. wxDateTime declares the following functions:
The wxDateTime data adapter is already part of the wxWidgets extension for rapidUI, so you don't actually have to define it yourself.

Q. What is the difference betweeen RapidUI and Data Binding?

Data Binding is a mechanism that binds a variable to a UI control. The value of the variable is transferred to the control when the control is initialised. The value is transferred back upon certain events, such as 'Apply' or closing a dialog.
RapidUI contains a data binding mechanism, but has more to offer. RapidUI adds 'rules' or 'contraints' to the 'property, method, event' paradigm. 'Rules' are expressions that are guaranteed to be valid at all times. Data Binding is just a special case of the RapidUI 'rules' mechanism. To bind a variable 'm_someVariable' to a control 'm_someControl', RapidUI uses a two-way rule: m_someVariable == m_someControl. Rules are guaranteed to be valid at all times. The RapidUI mechanism detects changes to either 'm_someVariable' or 'm_someControl' and updates the other object accordingly and automatically. The only work required from a programmer to achieve this is writing the rule and adding the variable and control to the rapidUI Mediator object.
RapidUI rules allow more flexibility and are much more powerful than a simple Data Binding mechanism. Rules can be almost any valid C++ expression.
Follwing are a few examples of rules:
Enabling a form
m_defectForm.Enabled = g_isRecordLoaded && g_accessRights[g_userLogin.group].m_canModifyData
The control Defect Form and all its children are enabled only if the global variable 'g_isRecordLoaded' is true and the current user belongs to a group with 'ModifyData' rights.
Validating two input values
true = in_range(0, 100, m_value1 + m_value2)
This validation rule ensures that the sum of 'value1' and 'value2' is between 0 and 100.
Executing an action
Add_Action.Fire = ID_ADD.Clicked
The action 'Add_Action' is executed when the control 'ID_ADD' is clicked, provided the action is enabled.
Enabling/Disabling an action
Add_Action.Enable = g_isRecordLoaded
The action 'Add_Action' is automatically enabled when g_isRecordLoaded is true and disabled when g_isRecordLoaded is false.

Q. I could simply buy a third party UI control (ActiveX control, plugin, whatever) that does what I want to. Why should I bother with RapidUI?

Visual Basic and .NET programmers are used to having a wide variety of third party ActiveX controls to choose from. These controls are certainly a good step towards reusable UI components. If you can find a control that does what you want to, use it. Compared to RapidUI they have several drawbacks.
You have to adopt their fixed interface
Controls you buy usually have a specific interface. To use them you have to write code that exchanges data between your program and their particular interface. You have to adapt your code to their interface. For example, if you buy and use a chart component, it expects data rows in a certain format. This format will be very different from your internal data representation. You have to write a for( ; ; ) loop to copy the data from your internal representation to their format. You can't just pass your own vector<>, list<>, wxList or ODBC data table to the control and expect it to work. But with RapidUI, thats exactly what you do.
In RapidUI the control adapts to your data structure. RapidUI contains data adapters even for high level constructs such as containers. If you are using STL containers in your code, defining a data adapter is done in one line of code. RapidUI has data adapters for ODBC data tables and it is quite easy to write your own adapters for text files or just about any other container implementation.
The effect is that you can code (or use) a UI control without any knowledge of the underlying container implementation and later use the control with such diverse implementations as C arrays (vectors), STL containers or even ODBC data tables. You simply pass a different data adapter to the control and thats all.

Q. What does the code look like? Can you give me an example?

Here is some RapidUI code straight out of the tutorial. The code 'assigns' a container to a listbox. All elements in the container are displayed in the listbox.
Define rules.
    RULE("m_channelsList.Items", make_expr<accessor>("m_channels"))         // listbox uses elements from m_channels
    RULE("m_channelsList.Column", make_const(string("m_title")))            // listbox displays "Channel::m_title"
    RULE("ID_FRAME.Title", make_const<wxString>("Headline: ")+make_expr<wxString>("m_channelsList.Current.m_title"))
    // the next rule connects the headlines listbox with the m_headlines
    // member of the currently selected channel
    RULE("m_headlinesList.Items", make_expr<accessor>("m_channelsList.Current.m_headlines"))
    // the following rule connects the content of the html window m_newsItem with
    // the body of the currently selected headline
    RULE("m_newsItem.Page", make_expr<wxString>("m_headlinesList.Current.m_body"))

Use a RapidUI object.

    m_rapidUI.AddWindow(this);                  // Add the main frame to RapidUI
    m_rapidUI.AddData(make_accessor(g_data));   // Add the list of channels
    m_rapidUI.AddRules(g_rules);                // Add rules
    m_rapidUI.Start();                          // Start the RapidUI mediator mechanism

Define data adapters.


The following code fragment enables a panel only if a checkbox is unchecked.

    RULE("m_controls.Enabled", !_e<bool>(_v("wnd::m_enable_controls")))

Q. Hm, this looks very complicated. How can this be faster than traditional coding?

The examples above use C++ syntax and macros to create rules, which makes the rules look more difficult than they actually are. Learning the C++ syntax is not hard, but writing rules will become even easier when the RapidUI rule parser has been implemented. For example, the rule in C++ syntax
Enable a control if a checkbox is unchecked
    RULE("m_controls.Enabled", !_e<bool>(_v("wnd::m_enable_controls")))

will then simply become

m_controls.Enabled = ! wnd::m_enable_controls

Filling a listbox with values from a vector<>

    RULE("m_channelsList.Items", make_expr<accessor>("m_channels"))         // listbox uses elements from m_channels

will become

m_channelsList.Items = m_channels

Q. Can you give a longer example?

Assume you want to create a dialog to let a user select and edit an email address.
  1. First create the email address data structure.
    struct EMailAddress {
        string  m_email;    // the email address
        string  m_name;     // the 'real' user name
        bool    m_htmlFmt;  // true if the user wants to receive mails in html
    Put this code in emailaddress.h

  2. Next create the data adapter for the struct and put it in emailaddress.cpp
  3. Create a global vector<EMailAddress> g_emailAddresses to store the email addresses and put it in emailaddress.cpp.
     vector<EMailAddress> g_emailAddresses;
  4. Define a data adapter for the vector<EMailAddress> container and put it in emailaddress.cpp.
  5. Use a GUI designer such as DialogBlocks (http://www.anthemion.co.uk/dialogblocks) to create a GUI.
    1. Put a listbox on the left and name it w_emailList
    2. Put two edit controls on the right below each other and name them w_email and w_name
    3. Put a checkbox on the right below the edit controls and name it w_htmlFmt
    4. Add three buttons: New, Save, Delete and name them w_add, w_save, w_delete
      Note: The names for the controls are similar to the names for the members in the struct except for the prefix: w_ for windows/controls and m_ for members. This is not a neccessity, simply a convention that rapidUI understands.

  6. Create rules that describe the behaviour and put them in emailaddressdialog.cpp (or any other convenient place):
    1. w_save.Enabled = w_emailList.Selected > 0
      enables the save button only when there is something to save. (Dirty flag handling is omitted here, but is something rapidUI can do.)
    2. w_delete.Enabled = w_emailList.Selected > 0
      Same with the delete button. Alternatively you could write:
      w_delete.Enabled = w_save.Enabled
    3. The Enabled attribute of the add button does not need a rule since it's always enabled.
    4. Now lets link the list to the vector of email addresses.
      This simple rule tells the rapidUI mechanism that the contents of the listbox w_emailList come from a container called g_emailAddresses. It also creates an iterator for the listbox that will always point to the selected element.
    5. Use this iterator to fill the rest of the controls:
      w_email = w_emailList.SelectedElement.m_email
      w_name = w_emailList.SelectedElement.m_name
      w_htmlFmt = w_emailList.SelectedElement.m_htmlFmt
      Put all of these rules in emailaddress.cpp
          RULE("w_save.Enabled", _e<int>("w_emailList.Selected") > 0)
          RULE("w_delete.Enabled", _e<bool>("w_save.Enabled") )
          RULE("w_emailList", "g_emailAddresses")
          TWOWAY("w_email", "w_emailList.SelectedElement.m_name")
          TWOWAY("w_name", "w_emailList.SelectedElement.m_name")
          TWOWAY("w_htmlFmt", "w_emailList.SelectedElement.m_htmlFmt")
  7. In the method where you want to open and display the dialog, create the dialog window and a rapidUI object:
    void EMailList::OnShowDialog()
            // create and load the dialog
        wxDialog dlg;
        wxXmlResource::Get()->LoadDialog(this, GetParent(), _T("ID_DIALOG"));
            // create the rapidUI object
        RapidUI m_rapidUI;
            // pass the window, the data and the rules to the rapidUI object
        m_rapidUI << dlg << make_container(g_emailAddresses) << emailAddressDlgRules;
            // activate rapidUI
            // show the dialog
What this does...
The code above will display the dialog, fill the list box with all elements from the global vector g_emailAddresses and select the first element in the list. Then, because of the linking rules, it will copy the contents of the first element in the vector to the controls email, name and htmlfmt. Finally it will enable the Save and Delete buttons.
When the user selects a new element, any changes made to the current element will be saved back and the new element will be selected. The same happens when the user closes the dialog.

Q. What license will the "Lit Window Library" be released under?

I have made no final decision about the license yet, but I am leaning towards the wxWidgets license.
Another possibility is this that the "Lit Window Library" will become two packages. The basic library containing data adapters and other useful stuff is completely independent of wxWidgets. This part, lwbase, might be released under a very open license, possibly the same license as the STL or the BOOST library. The GUI framework dependent part, lwwxwidgets, would then be released under the wxWidgets license.

Q. Will RapidUI work with other GUI Frameworks besides wxWidgets? What about Qt? MFC?

Quite possibly, if someone writes the neccessary adapters for it.
The Lit Window Library is actual a package of several libraries. The base library, lwbase, is completely independent from any GUI stuff. The GUI dependent part, lwwxwidgets, is designed in a manner that makes porting to a different UI framework possible.

Q. I have some suggestions and/or more questions. How can I contact you?

Please send ideas, suggestions and encouragement to Hajo at
library (at) litwindow (dot) com

Q. I want to contribute. How can I help?

Answer: Giving feedback
By giving feedback and encouragement. I would especially like to hear why you think the idea presented might not work. Where do you see difficulties? What do you think might hinder using the library in actual projects? Any kind of critisism - as long as it is constructive - is helpful.
There have been efforts like this in the past, but I know of none that actually succeeded to the point that many people are actually using it. If you have heard of such an effort and have an idea why it failed, please let me know.
Identifying UI Patterns
The library shall contain ready-to-use components for common UI patterns. I am compiling a list of common UI patterns and need input. The patterns I am talking about are simply commonly used UI mechanisms. Here are some examples:
I hope you get the picture. What common UI tasks have you solved and what UI pattern was behind it? What would you like to see as a ready-to-use component in a library?
Help with coding, documenting, releasing etc...
The material presented here is still under heavy development. I think the current stage is already beyond the 'proof of concept', if barely. But there remains a lot to be done.

Q. Who is behind "Lit Window Productions"? Who are you?

"Lit Window Productions" creates and sells tools for developers. If you are interested, please have a look around:

On the website you will also find tips&tricks and howtos for wxWidgets and development in general. http://www.litwindow.com

My name is Hajo Kirchhoff. I have been writing software since 1985. In recent years I have added coaching to contract work, teaching "Best Practices" in project management and software development to individuals and groups of developers. http://www.litwindow.com/About/about.html contains the contact details.

wxConfigBase &cfg=*wxConfigBase()::Get();
cfg.Read("/settings/m_timeout", &g_settings.m_timeout);
cfg.Read("/settings/m_address", &g_settings.m_address);
*wxConfigBase::Get() >> make_accessor(g_settings);

Copyright 2004, Hajo Kirchhoff, Lit Window Productions