About the Visual Component Framework
The Visual Component Framework was inspired by the ease of use of environments like NeXTStep's Interface Builder, Java IDEs like JBuilder, Visual J++, and Borland's Delphi and C++ Builder. I wanted a generic C++ class framework I could use to build apps quickly and visually (when designing GUIs), as well as have the core of the framework be as cross platform as possible. The Visual Component Framework is an Open Source project, so feel free to grab and use it if you think it might be useful. If you're really adventuresome, you can volunteer to help develop it, making it even better, especially in tying it into the VC++ environment as an add-in. For more information on either the project, helping out, or just browsing the doxygen generated documentation, please go to the VCF project on Source Forge here, or the project website. The code is available from CVS (follow the how-to here for setting up CVS on Windows), or as a tar.gz file in the files section of the project.
Introduction
This article will expand what we accomplished in "Hello World with the VCF 2", namely by expanding our application class, and deriving our first visual component, our own custom Window
based class. In addition, we will also see some new functions like the StringUtils::trace
functions.
The last article finished off with some code that looked something like this:
class HelloWorld2Application : public Application {
public:
HelloWorld2Application () {}
virtual ~HelloWorld2Application () {}
virtual bool initRunningApplication(){
bool result = Application::initRunningApplication();
Window* mainWindow = new Window();
setMainWindow( mainWindow );
Rect mainWindowBounds( 100.0, 100.0, 500.0, 500.0 );
mainWindow->setBounds( &mainWindowBounds );
mainWindow->show();
return result;
}
};
int main(int argc, char *argv[])
{
HelloWorld2Application app;
Application::appMain( argc, argv );
return 0;
}
We're going to enhance this by adding our own custom Window class as follows:
class HelloWorld3Window : public Window {
public:
HelloWorld3Window() {
Application* runningApp = Application::getRunningInstance();
String appClassName = runningApp->getClassName();
setCaption( appClassName + " - Hello World!" );
Rect bounds( 100.0, 100.0, 500.0, 500.0 );
setBounds( &bounds );
StringUtils::traceWithArgs( "HelloWorld3Window constructor @%p,
bounds: %s\n", this,
bounds.toString().c_str() );
setVisible( true );
}
virtual ~HelloWorld3Window(){};
};
In our example, we need a constructor and destructor defined. In our constructor, we are going to perform the window initialization that we had previously done in the initRunningApplication()
method of our HelloWorld2Application
application class. The first thing we are going to do is put a string together that will represent the class name of our current application class and "Hello World". To get the running application instance in a process, we just call the static method Application::getRunningInstance()
, which will return a pointer to the currently running Application
derived instance. We then get the class name of the application class, and set the caption of our window, appending "Hello World" to it as well.
Once again, we set the bounds of the Window
via the setBounds()
method, as in our previous examples. After doing this, we then output a trace to the debugger, using the ever handy StringUtils
class. The StringUtils
class has a series of string utility functions, one of which allows the programmer to output a string, or a string plus variable arguments (ala printf()
). In our case, we use the variable argument function StringUtils::traceWithArgs()
, giving us information about the window pointer and the current bounds Rect
.
Our final act is to actually display the window, this time using the setVisible()
method and passing in true.
This gives us our window class, now let's look at our application class:
class HelloWorld3Application : public Application {
public:
virtual bool initRunningApplication(){
bool result = Application::initRunningApplication();
m_tmpDummyBuffer = new char[4096];
Window* mainWindow = new HelloWorld3Window();
setMainWindow(mainWindow);
return result;
}
virtual void terminateRunningApplication() {
delete [] m_tmpDummyBuffer;
m_tmpDummyBuffer = NULL;
StringUtils::trace( "HelloWorld3Application::terminateRunningApplication()"\
"cleaned up memory\n" );
Application::terminateRunningApplication();
}
char* m_tmpDummyBuffer;
};
Like our previous class, we have overridden the initRunningApplication()
method. But we also introduce overriding the terminateRunningApplication()
method. Overriding this allows you to perform your own application specific clean up in a graceful manner. In our example, we allocate a dummy buffer of 4,096 bytes on the heap, and assign it to the m_tmpDummyBuffer
member variable in our initRunningApplication()
. Then in the terminateRunningApplication()
, we clean up the memory, output some info, and call the super class' terminateRunningApplication()
. Both initRunningApplication()
and terminateRunningApplication()
are called by the framework for you during the initialization and termination of your application.
In addition to allocating our dummy variable, we also create our main window in our initRunningApplication()
. Whereas the previous example had created a window, and then set a number of properties on it, here we just create a new instance of our HelloWorld3Window
class, and let the HelloWorld3Window
constructor take care of the rest.
So we have seen how to not only customize our application class further, but have also created our first VCF Window derived class! And hopefully all without breaking a sweat!