V - A Free C++ Graphical User Interface FrameworkWritten by Jon Hacker |
[Note: You can download the latest version of V from the V
distribution site.
- Ed.]
IntroductionV, a completely free cross-platform C++ Graphical User Interface Framework, is an easy to use programming system for building GUI applications. The second major upgrade to the OS/2 port of V was released this past February. The framework is small, elegant, and provides the tools required for building all but the most specialized applications. The V framework has also been designed to be portable, yet present a look and feel consistent with native applications. Currently, besides the OS/2 port, versions for the X Windowing System, Microsoft Windows 3.1, and Microsoft WIN32 (Windows 95 and NT) are available. The V system is freely available for use by anyone under the terms of the GNU Library General Public License. To give you some idea of the capabilities of V, a screen shot of a V-based application demonstrating the built-in OpenGL canvas is shown here running on OS/2. The total size of all the source code files needed to build this application is less than 15 kB, including both comments and the OpenGL code for creating and spinning the image.
History of VV was conceived and developed by Bruce Wampler after he became tired of complicated, difficult to learn and use libraries for building interfaces, and wanted something easier. Bruce originally wrote V for the X and Windows 3.1 platforms. It was later ported to Win32. The OS/2 port was done separately by myself with the first release in February 1998. All ports continue to evolve and develop in a unified manner.The main design goal for V is ease of programming. It is not reasonable that building the GUI part of an application should be the hardest part of the job, as is the case with most native GUI toolkits. V is small, easy to learn, easy to use, and provides the essentials of a good graphical user interface. V has less than 15 C++ classes that you will have to interact with. This is unlike many other frameworks that provide dozens and dozens of classes which you must learn and understand. The V framework only supports GUIs. It does not have templates, containers, and all kinds of other C++ classes. If you need a good list class, deploy your favorite one from another class library. Use V for your interface. V has very good associated documentation. One reason V is easy to use is that it is accompanied by an above-average programming manual written as a well-organized hypertext HTML document. Each V class and function has not only a useful explanation, but also each description comes with a short example that shows how to use the V feature in a useful way. There are also several examples provided with the V distribution to help you get started with a basic V application. For application development V includes an application generator (vgen) and an integrated development tool (vide) to help simplify the coding process. Vgen builds the required skeleton code to support your application after you define the basic windows and dialogs that you need. Vide is useful as a project manager and editor for developers who do not use commercial IDE tools, or for those who just want something they can customize to their own liking. Both are written as V applications and the complete source code is included. A screen shot of the application generator is shown here running on OS/2.
There is, of course, a price to pay for the ease of programming with V. The main constraint is that you are somewhat restricted to following V's view of the world. The V model does not exactly conform to the native models of OS/2, Windows, and X, but it is a very good compromise. For the most part applications developed with V will in fact conform to the host look and feel, but may be lacking some of the bells and whistles of the most sophisticated commercial applications available for a given platform. For the vast majority of applications, this will not matter. You will end up with applications that look pretty good, and are likely to have a much cleaner and better interface than they might have otherwise. If you are a C programmer, then the fact V is a C++ library might be a problem. While it is a fully object-oriented C++ framework, it can be used with C code if you know a bit about C++. Also, V does not allow you to do everything you could if you programmed in the native windowing library. You won't have every single conceivable control, and some controls are slightly restricted in how you can use them. Getting Started with VAs with any new system, V has a learning curve before you can write applications of your own. V's learning curve is actually pretty short. Experience has shown the best way to get started with V is to step through an example V application.The V application generator, vgen, included with the V distribution is the easiest way to start building a V application. Run vgen, select the basic options you want to include in your application, select the directory to save the generated code in, and then generate the basic skeleton application. From the skeleton app, it is relatively easy to add your own functionality. The tutorial application described in the next section is also an excellent V example. Start by getting the example to compile. Then modify the code to add or remove features. Before long, you will have a good feel for V, and be able to add all the features you need. Before we leap into an example, though, let's first describe in general
terms the main pieces that form the core of a typical V application
and how they interact with one another.
The vApp class has several utility methods that are usually
used unmodified, plus several methods that are generally overridden by the
myApp
class. In addition, your myApp class will normally have several
other programmer-defined methods for interfacing the command windows
with the application model.
Since a vCmdWindow contains different panes such as vMenus (for pulldown and popup menus), vCanvasPanes (for drawing graphics and displaying text in a window), vCommandPanes (for toolbars), and vStatusPanes (for status bars), your top-level command window object will usually define the appropriate pointers to each of these objects as required by the specific application. The myCmdWindow constructor will then have a new for each pane used. Each instance of a window will be built using a call to the vApp::NewAppWin method. This allows the app object to track windows and control interaction between the app model and the views represented by each window. Some applications need to open subwindows. These windows may or may
not use the same menu, command bar, and canvas as the top-level window.
If they do, then they can use the same static definitions as the top-
level window. Subwindows may also have their own menu, button, and canvas
definitions.
The top-level window (or the subwindow that defines and uses the dialog) will create an instance of each dialog it needs (via new). The constructor for the dialog sets up the commands used for the dialog. Typically, the top-level window defines menu and button commands that
result in the creation of a dialog. The top-level window is thus usually
responsible for invoking dialogs.
A Tutorial V ApplicationNow that you have read about the parts of a standard V application, it will be useful to go over a bare-bones example to make our theoretical discussion more concrete. Included with the V installation are a number of applications, each in its own subdirectory. We will focus our attention here upon one of the simplest V examples provided. It is called tutapp, and the source code can be found in the V\tutor\ directory. The code is written clearly to serve as a tutorial, and is well commented. You can read the code on your own to get a good understanding of what elements are required for a V application. Before you go off on your own and read it over though, I will first try to provide an overview of the tutapp source code focusing mainly upon those parts of the code that are particularly noteworthy.To compile the tutapp application you can use the appropriate makefile for your compiler. IBM VisualAge users can find the makefile vtutor.mak in the directory V\ibmcpp. Instructions for local configuration of the makefile for your system can also be found in V\ibmcpp. EMX users can use the makefile in the V\tutor\ directory, after first editing the configuration file config.mk following the instructions in the readme file in the subdirectory V\emx. Borland C++ users can find the tutor.prj project file in V\bcos2. You will probably need to edit the project settings to match your local directory structure. Watcom users will find only limited support so far in V\watos2. However, that will be corrected with the next release as I have now received a complete set of project files from Herbert Bushong for Watcom 11.0.
The previous section suggested using myApp for names. This
tutorial uses a t prefix instead of my. You really can
use whatever names you want. It helps to be consistent, however.
The single definition of the application tut_App("TutorApp"), and the AppMain main function are also in this file. One thing that can be difficult to grasp when using a framework such as V is understanding where the program starts, and how you get things rolling. This happens in tutapp.cpp, so it is especially important to understand this piece of code. The essential thing to understand is that C++ will invoke the constructors of static objects before beginning execution of the program proper. Thus, you declare a static instance of the vApp object, and its constructor is used to initialize the native GUI library and get things going. Your program will not have a main() function, but something similar in spirit is provided by the V function called AppMain(). The initial window is created in AppMain by calling NewAppWin as shown below. Note the use of the automatically defined global pointer theApp that is used to access vApp methods from inside Appmain. static tutApp tut_App("TutorApp"); // The single instance of the app //===========================>>> AppMain <<<============================== int AppMain(int argc, char** argv) { // The V framework defines the instance of main. After some // processing of command line arguments, AppMain is called with // cleaned up command line arguments. Note that at this time, no // windows have been defined. Normally, AppMain is the place to // start up the first window. You can perform any initialization you // need to do here. (void) theApp->NewAppWin(0, "Tutorial V Example", 350, 100, 0); // At this point, the window is up, and all events are being // routed through its methods. // We MUST return 0 if the status is OK at this point. return 0; }
// Now, the static declarations of the menu arrays. You first define // the pulldown menus, one for each main menu bar label. static vMenu FileMenu[] = // Items for File menu { {"New",M_New,isSens,notChk,noKeyLbl,noKey,noSub}, {"Open",M_Open,isSens,notChk,noKeyLbl,noKey,noSub}, {"Save",M_Save,notSens,notChk,noKeyLbl,noKey,noSub}, {"Save As",M_SaveAs,notSens,notChk,noKeyLbl,noKey,noSub}, {"-",M_Line,notSens,notChk,noKeyLbl,noKey,noSub}, {"Debug",M_SetDebug,isSens,notChk,noKeyLbl,noKey,noSub}, {"-",M_Line,notSens,notChk,noKeyLbl,noKey,noSub}, {"Exit",M_Exit,isSens,notChk,noKeyLbl,noKey,noSub}, {NULL} };Toolbars (command bars in V terminology) and status bars are defined in a like manner. Again, each line represents a CommandObject (control), and various flags and variables define its id and initial attributes. Position is controlled by the order in which the controls are specified, starting from the left and working towards the right. Of course, methods are also provided to modify and interact with the controls dynamically as the code runs. In this code segment, a command bar consisting of a text label followed by a row of four pushbuttons is defined. // We now define a command bar. Command bars are optional, and there // may be more than one. You can place any CommandObject you want on a // command bar. static CommandObject CommandBar[] = // A simple command bar { {C_Label,999,0 ,"Command Bar",NoList,CA_None, isSens,NoFrame,0,0}, {C_Button,M_Copy,M_Copy,"Copy",NoList,CA_None, notSens,NoFrame,0,0}, {C_Button,m_Dialog,m_Dialog,"Dialog",NoList,CA_None, isSens,NoFrame,0,0}, {C_Button,m_Clear,m_Clear,"Clear",NoList,CA_None, isSens,NoFrame,0,0}, {C_Button,M_Exit,M_Exit,"Exit",NoList,CA_None, isSens,NoFrame,0,0}, {C_EndOfList,0,0,0,0,CA_None,0,0,0} // This ends list };Once the static definitions for the various panes are defined, the panes are added to the window using the AddPane() function. This is typically done in the constructor for the command window as shown below for the command pane (CommandBar) we defined above. // Create and add the command pane to this window myCmdPane = new vCommandPane(CommandBar); AddPane(myCmdPane);There is also code to demonstrate handling keyboard and window command events in the KeyIn and WindowCommand methods. There is also a simple example of using the vFileSelect utility class, as well as invoking modeless and modal dialogs.
//========================>>> tCanvasPane::Redraw <<<===================== void tCanvasPane::Redraw(int x, int y, int w, int h) { // This is a simple Redraw that just redraws everything. // Often, that will be more than fast enough, but the input // parameters can be used to make a more intelligent redraw. for (int i = 0 ; i < _nextpt ; i += 2) DrawLine(_pt[i].x, _pt[i].y, _pt[i+1].x, _pt[i+1].y); }
static CommandObject DefaultCmds[] = { {C_Label, mdLbl1, 0,"X",NoList,CA_MainMsg,isSens,NoFrame, 0, 0}, {C_Frame,mdFrmV2,0,"",NoList,CA_None,isSens,NoFrame,0,mdLbl1}, {C_Label,mdLbl4,0,"Buttons",NoList,CA_None,isSens,mdFrmV2,0,0}, {C_Button,mdBtn1,mdBtn1,"Button 1",NoList,CA_None,isSens,mdFrmV2,0,mdLbl4}, {C_Button,mdBtn2,mdBtn2,"Button 2",NoList,CA_None,isSens,mdFrmV2,0,mdBtn1},Once the static data is defined, the dialog is built in the dialog constructor by using the AddDialogCmds() function and feeding it the static definition of the dialog (DefaultCmds)we defined above. tDialog::tDialog(vBaseWindow* bw) : vDialog(bw) { // The constructor for a derived dialog calls the superclass // constructor, and then adds the command objects to the dialog // by calling AddDialogCmds. AddDialogCmds(DefaultCmds); // add the command objects }To display the dialog, our application first defines an instance of the desired dialog in its command window constructor. For our example, this is the tCmdWindow constructor found in tcmdwin.cpp. // In the V model, a window may have dialogs. Each dialog used // by a window must have an instance pointer. The easiest way // to create dialogs is to construct each one using a new here // which only defines the dialog - you need to use its // ShowDialog method at the appropriate time to display it). // You delete dialogs in the destructor for this window. // // Now, create whatever dialogs this app defines: sampleDialog = new tDialog(this);To actually display the dialog, typically the user does something that then invokes the ShowDialog method. In our example, the user selects the menu item defined as m_Dialog to open the dialog. The actual code that does the work is in the WindowCommand() method for our main window in the file tcmdwin.cpp as shown below. case m_Dialog: // Invoke our dialog { if (!sampleDialog->IsDisplayed()) // not twice! sampleDialog->ShowDialog("Sample Modeless Dialog"); break; }
case m_ModalDialog: // Invoke our modal dialog { ItemVal val, id; id = sampleModalDialog->ShowModalDialog("Sample Modal",val); // Now do something useful with id and val ... break; } ConclusionWhile this article has tried to gently introduce the programming concepts of V, experience suggests that the only way to truly learn is to jump right into the code and try compiling your own. A good place to start is with the tutorial application described above. You should study this code, paying special attention to the comments, and start by making a simple modification such as adding an extra button to the tool bar . Most of the information you need to build a typical V application is explained in this code and you will quickly find coding with V to be easy and fast.Users can also join the V mailing list to interact with
other V users, ask for and give technical support to others,
and discuss new features to be added in the future. To subscribe send email
with the subject "subscribe" to
For regular postings please use vgui-discuss@other.debian.org. Back issues of the list are archived on www.debian.org/Lists-Archives/ I hope you enjoyed this article and now have a better understanding
of how to build V applications. Be sure to visit the V
Gui Home Page ( http://objectcentral.com/)
to download the latest version of V and keep informed
about the latest V news.
|