Introduction
It is always difficult to start a new article and the first question that arises is what to title it. I must admit that this time I have been a bit pretentious but my first goal was to provide a new framework based on an XML description (like XUL or XAML). Actually I started to develop with MFC two years ago and like every newbie I had to fight even to do simple operations (display different kinds of pictures: BMP, JPEG, animated GIF, change font...) and I still don't understand why it is always so difficult to do simple things. Besides recently a friend of mine showed me another IDE (Borland C++) and I was very impressed by the number of properties available by default. These reasons convinced me to start this project.
Before starting, I studied all the "dynamic screen" projects and I found very interesting materials in the following articles and my project is more or less based on them.
Note: In this article, I am using XUIxxx
but I have still not renamed all my classes so actually you have to translate it in GUI or Dyn. In any case, if you are not interested in the whole project you may find some interesting parts like the use of CxImage
to display pictures in the widgets folder.
Architecture
This project tries to use an OO approach and could be described in modules. I tried to use platform independent libraries and in particular the widget manager uses the STL.
There are mainly four parts:
- An XML parser: I am using TinyXml because it is portable (Windows XP/CE, Unix) and uses a logical approach. XML is used to save and load widget properties. For instance, if you put a Static in the form with a red background color, it will be saved as:
<object class="Static" name="ID_STATIC_1003">
<id>1003</id>
<pos>73,34</pos>
<size>265,154</size>
<caption>Hello Code Project</caption>
<background FillMode="0" LowColor="0x0000ff" HiColor="0x0000ff" />
</object>
The format used looks like the one in use in WxWidgets and it's not surprising because my main goal is to do the porting to this framework.
- A class to handle settings (
CSettings
): Actually this class is what is called a Singleton in design patterns and it means that you can instantiate it only once. You can call a pointer on it from everywhere you want in your code as long as you include its header file (it's a kind of improved global variable, I am saying that for people coming from C). I am talking about this class, but in this project I am not using it. - A properties manager using
PropertyViewLib
: This class is used to display widget properties. To do so, each widget derives from it and implements two methods: GetProperties()
and PropertyChanging()
. GetProperties(...)
is used to add/remove fields from the properties toolbar while PropertyChanging
is called every time you modify a property. - A templated class deriving from
CWnd
and that allows integration in CView
derived projects as well as in dialogs (see DynScreen on CodeProject): This class stores a list of GUI elements that represent a widget object. Every widget derives from this class.
For now I have only implemented frame and label widgets but if you are interested to add buttons, edit boxes and so on, you need to create a class deriving from XUIElements
and create a class deriving from the object you want. Let's say you want to add edit controls, create a class XUIEdit
deriving from XUIElements
and have a look at XUIStatic
to understand how it works.
Using the Framework
The framework is currently in pre-alpha release. It means that if you want to integrate it in your projects, you need to understand a bit of what is going on and it's not as easy as it should. Now if you are motivated, you can start GuiBaker and create your layout. Here is the sequence:
- Start GuiBaker.exe: If it's the first time, it will warn you that there is no config file and will create one for you.
- Go to Window->Screen Designer to go to edit mode and add your widgets.
- When you have finished, go back to Window->Screen Designer and automatically your GUI will be saved in the current folder as gui.xui.
- If you restart GuiBaker.exe, your GUI is reloaded.
Once the layout is defined, you need to integrate CDynWnd
(will be renamed in CXuiWnd
in future) in your project. You can have a look at TestView.h and TestView.cpp to see how to do it. For easier integration, you should remove all the parts corresponding to the editor (OnButtonlabel
, OnButtonLeftAlign
, OnButtoncombo
, ...) and just keep the minimum. Finally in your OnInitialUpdate
, call the base method like this:
void CTestView::OnInitialUpdate()
{
CDynWnd<CView>::OnInitialUpdate(_T("gui.xui"));
m_staFlecheD = XUICTRL(*this, "ID_FLECHED", CxStatic);
m_staFlecheG = XUICTRL(*this, "ID_FLECHEG", CxStatic);
m_staDisplay = XUICTRL(*this, "ID_DISPLAY", CPPHtmlStatic);
m_staLabel7 = XUICTRL(*this, "ID_LABEL7", CxStatic);
m_staLabel8 = XUICTRL(*this, "ID_LABEL8", CxStatic);
if (m_staFlecheD == NULL || m_staFlecheG == NULL ||
m_staDisplay == NULL || m_staLabel7 == NULL ||
m_staLabel8 == NULL)
return;
m_staDisplay->SetBkColor(RGB(255,255,255));
m_staDisplay->SetFont("Arial", 60, FW_BOLD);
m_staLabel7->SetTransparent(TRUE);
m_staLabel7->SetFont("Arial", 18, FW_BOLD);
m_staLabel8->SetTransparent(TRUE);
m_staLabel8->SetFont("Arial", 18, FW_BOLD);
}
As you can see, you can get a pointer on a widget by using the MACRO XUICTRL
and changing its properties dynamically.
Issues
I initially wanted to offer the user the possibility to choose between two kinds of GUI: one based on a dialog and another on CView
. However for now all the widgets (Xuielements
) use the CView
as parent because I cannot solve the problem regarding the Z-order. I have tried to implement a method to put an element to back or to front but it doesn't seem to work (see OnSetTopWnd()
in DynWnd.h). Another improvement would be to use the GuiLib to have the same aspect as Visual Studio and it would be more professional but I prefer first to have all the functionalities working and after to work on the visual aspect.
History
- GuiBaker v0.1: Initial release
- 4th August, 2010: Updated project to be able to compile with VS2010
TO-DO
- Write a better article to show the interesting points and how it can simplify development
- Separate GuiBaker (tool to design layout) and classes for easier integration
- Rename GUIxxx to XUIxxx,
CdynWnd
-->CXuiWnd
, ... - Add a class
CStrConv
with static methods to use with XML (improve readability) - Change wigdet tracking and integrate qtrectracker to allow display of widgets at any angle
- Write Windows CE/Pocket PC class to load XUI files (first step, compile TinyXml and
CxImage
for WinCE)