The V C++ GUI Framework:vApp

From EDM2
Jump to: navigation, search

vApp

The base class for building applications.

Synopsis

Header:
[vquickr.htm#vApp <v/vapp.h>]
Class name:
vApp
Contains:
vCmdWindow, vAppWinInfo

Description

The vApp class serves as the base class for building applications. There must be exactly one instance of an object derived from the vApp class. The base class contains and hides the code for interacting with the host windowing system, and serves to simplify using the windowing system.

You will usually derive a class based on vApp that will serve as the main control center of the application, as well as containing the window objects needed for the user interface. The single instance of the application class is defined in the body of the derived application class code.

The vApp class has several utility methods of general usefulness, as well as several methods that are normally overridden to provide the control interface from the application to the command windows. The derived class will also usually have other methods used to interface with the application.

In order to simplify the control interface between the application and the windows, the vAppWinInfo class has been provided. The application can extend that class to keep track of relevant information for each window. When the NewAppWin method is used to create a window, it will create an appropriate instance of a vAppWinInfo object, and return a pointer to the new object. The base vApp then provides the method getAppWinInfo to retrieve the information associated with a given window.

Constructor

vApp(char* appName)

vApp(char* appName, simSDI = 0, int fh = 0, int fw = 0)

appName

Default name for the application. This name will be used by default when names are not provided for windows. The name also appears on the main window for some platforms, including Microsoft Windows, but not X. The constructor also initializes some internal state information. There must be exactly one instance of the vApp object, and will usually represent your derived myApp object. See the code below with AppMain for an example of creating the single app instance.

simSDI

This optional parameter is used to specify that V should start as a Windows SDI application if it is set to 1. This parameter has no effect for the X version.

fw, fh These are used to specify the size of a menuless and canvasless V application, and are optional.

Methods to Override

void AppCommand(vWindow* win, ItemVal val)

Any window commands not processed by the [vWindow] object are passed to AppCommand. You can override this method to handle any commands not processed in windows.

int AppMain(int argc, char** argv)

This is a global function (not a class member!) that is called once by the system at start up time with the standard command line arguments argc and argv. You provide this function in your code.

Your program will not have a C main function. The main reason for this is portability. While you would usually have a main in a Unix based program, MS-Windows does not use main, but rather PASCAL WinMain. By handling how the program gets started and providing the AppMain mechanism, V allows you to ignore the differences. You will still have all the capability to access the command line arguments and do whatever else you would do in main without having to know about getting the host windowing system up and running.

The windowing system will have been initialized before AppMain is called. You can process the command line arguments, and perform other required initializations. The top level command window should also created in AppMain by calling NewAppWin.

Before AppMain is called, the single instance of your derived vApp object must also be constructed, usually by instantiating a static instance with a statement such as static myApp* MyApp = new myApp("ProtoApp"). As part of the construction of the myApp object, the global pointer vApp* theApp is also pointed to the single instance of the vApp or derived myApp object. You can then use theApp anywhere in your code to access methods provided by the vApp class.

Your AppMain should return a 0 if it was successful. A nonzero return value will cause the V system to terminate with an exit code corresponding to the value you returned.

Example

// EVERY V application needs the equivalent of the following line

  static myApp myApp("My V App");  // Construct the app.

//==========================>>> AppMain <<<===========================
  int AppMain(int argc, char** argv)
  {
    // Use AppMain to perform special app initialization, and
    // to create the main window.  This example assumes that
    // NewAppWin knows how to create the proper window.

    (void) theApp->NewAppWin(0, "My V App", 350, 100, 0);
    return 0;
  }

int CloseAppWin(vWindow* win)

This is the normal way to close a window. Your derived CloseAppWin should first handle all housekeeping details, such as saving the contents of a file, and then call the default vApp::CloseAppWin method. Your code can abort the close process by not calling the default vApp::CloseAppwin class, and instead returning a 0. When you call the default method, the window's CloseWin method is called and the window removed.

The CloseAppWin method is also called when the user clicks the close button of the window. This close button will correspond to the standard close window button depending on the native windowing system. On X Windows, this button will depend on what window manager you are using. On Windows, this corresponds to a double click on the upper left box of the title bar, or the ``X box in Windows 95. To abort this "close all" procedure, return 0 from your class.

Example

//======================>>> videApp::CloseAppWin <<<===========================
  int videApp::CloseAppWin(vWindow* win)
  {
    // This will be called BEFORE a window has been really closed.

    videCmdWindow* cw = (videCmdWindow*)win; // get our cmd window
    if (cw->CheckClose())                    // check if OK to close
        return vApp::CloseAppWin(win);       // if OK, then call vApp method
    else
        return 0;                            // otherwise, abort close process
  }

int CloseLastCmdWindow(vWindow* win, int exitcode)

This method is provided mainly for MS-Windows MDI compatibility. The default behavior of V is to close the app when the last MDI child window is closed. This corresponds to what would happen on the X version. However, this is not standard behavior for Windows MDI apps.

If your app needs standard Windows behavior, then you should override CloseLastCmdWindow, and simply return. This will result in an empty MDI framw with a single active File menu with the commands New, Open, and Exit. You should also then override vApp::AppCommand to handle the New and Open cases. It will be harmless to duplicate this code for X apps.

The following code sample, taken from the V Text Editor code, shows how to get standard MDI behavior in a way that is compatible with both Windows and X.

//======================>>> vedApp::AppCommand <<<===========================
  void vedApp::AppCommand(vWindow* win, ItemVal id, ItemVal val, CmdType cType)
  {
    // Commands not processed by the window will be passed here
    // switch is used to handle empty MDI frame commands New and Open
    // for Windows apps only. Harmless on X.

    UserDebug1(Build,"vedApp::AppCmd(ID: %d)\n",id);
    switch (id)
      {
        case M_New:
          {
            (void*) theApp->NewAppWin(0, "V Text Editor", 100, 50);
            return;
          }

        case M_Open:
          {
            vedCmdWindow* cw;
            cw = (vedCmdWindow*) theApp->NewAppWin(0, "V Text Editor", 100, 50);
            cw->WindowCommand((ItemVal)M_Open,(ItemVal)0,(CmdType)0);
            return;
          }
      }

    vApp::AppCommand(win, id, val, cType);
  }

//===================>>> vedApp::CloseLastCmdWindow <<<======================
  void vedApp::CloseLastCmdWindow(vWindow* win, int exitcode)
  {
#ifndef V_VersionWindows
    vApp::CloseLastCmdWindow(win,exitcode);   // call default for X
#endif
  }

void Exit(void)

This is the normal way to exit from a standard V application. The overridden method can perform any special processing (e.g., asking ``Are you sure?) required. The default Exit will call CloseAppWin for each window created with NewAppWin, and then exit from the windowing system.

void KeyIn(vWindow* win, vKey key, unsigned int shift)

Any input key events not handled by the vWindow object are passed to VApp::KeyIn. See KeyIn in the vWindow section for details of using keys.

vWindow* NewAppWin(vWindow* win, char* name, int w, int h, vAppWinInfo* winInfo)

The purpose of the NewAppWin method is to create a new instance of a window. Most likely, you will override NewAppWin with your own version, but you still must call the base vApp::NewAppWin method after your derived method has completed its initializations.

The default behavior of the base NewAppWin class is to set the window title to name, and the width w and height h. Note that the height and width are of the canvas, and not necessarily the whole app window. If you don't add a canvas to the command window, the results are not specified. Usually, your derived NewAppWin will create an instance of your derived vCmdWindow class, and you will pass its pointer in the win parameter. If the the win parameter is null, then a standard vCmdWindow will be created automatically, although that window won't be particularly useful to anyone.

Your NewAppWin class may also create an instance of your derived vAppWinInfo class. You would pass its pointer to the winInfo parameter. If you pass a null, then the base NewAppWin method also creates an instance of the standard vAppWinInfo class.

The real work done by the base NewAppWin is to register the instance of the window with the internal V run time system. This is why you must call the base NewAppWin method.

NewAppWin returns a pointer to the object just created. Your derived code can return the value returned by the base vApp::NewAppWin, or the pointer it created itself.

Example

The following shows a minimal example of deriving a NewAppWin method.

vWindow* myApp::NewAppWin(vWindow* win, char* name, int w, int h,
  vAppWinInfo* winInfo)
  {
    // Create and register a window. Usually this derived method
    // knows about the windows that need to be created, but
    // it is also possible to create the window instance outside.

    vWindow* thisWin = win;
    vAppWinInfo* theWinInfo = winInfo;

    if (!thisWin)   // Normal case: we will create the new window
        thisWin = new myCmdWindow(myname, w, h);  // create window

    // Now the application would do whatever it needed to create
    // a new view -- opening a file, tracking information, etc.
    // This information can be kept in the vAppWinInfo object.

    if (!theWinInfo)               // Create if not supplied
        vAppWinInfo* theWinInfo = new myAppWinInfo(name);

    // Now carry out the default actions
    return vApp::NewAppWin(thisWin, name, w, h, theWinInfo);
  }

Utility Methods

char* ClipboardCheckText()

Returns 1 if there is text available on the clipboard.

void ClipboardClear()

Clears the contents of the clipboard. Deactivates M_Paste.

char* ClipboardGetText()

If there is text on the clipboard, this method will return a pointer to that text.

int ClipboardSetText(char* text)

This will set the system clipboard to the value of text. It will also send a vApp::SetValueAll message to each of your windows to set any command object M_Paste to sensitive. (Whenever the clipboard is emptied, a message to set M_Paste insensitive is also sent.)

Note that it is up to you to implement clipboard interaction. The vTextCanvasPane does not provide automatic clipboard support. Thus, your app needs to respond to cut, copy, and paste commands. The clipboard code will send a message to your Command Window to control the sensitivity of the M_Paste command.

int DefaultHeight()

Returns a default window canvas height value in pixels corresponding to 24 lines of text in the default font.

int DefaultWidth()

Returns a default window canvas width value in pixels corresponding to 80 columns of text in the default font.

vFont GetDefaultFont(void)

This method returns a vFont object representing the default system font. It is a convenience method, and probably not overly useful to application programs.

vFont GetVVersion(int& major, int& minor)

Returns the current major and minor version of V.

int IsRunning()

This method returns true if the windowing system is active and running. A false return means the program was started from a nonwindowing environment.

int ScreenHeight()

Returns the overall height of the physical display screen in pixels. Note that this value may or may not be overly useful. On X, the vCommandWindows are drawn on the full display. On the Windows MDI version, the command windows all fall inside the MDI frame, and thus knowing the size of the whole screen is less useful.

int ScreenWidth()

Returns the overall width of the physical display screen in pixels. See ScreenHeight.

void SendWindowCommandAll(ItemVal id, int val, CmdType ctype)

This method can be used to send a message to the WindowCommand method of ALL currently active windows. This method is most useful for sending messages to windows from modeless dialogs. While messages to the WindowCommand method usually originate with the system in response to menu picks or command object selection, it can be useful to send the messages directly under program control. The vDraw sample program contains a good example of using SendWindowCommandAll (and SetValueAll) in vdrwdlg.cpp. There is no way to send a message to a specific window. The message is sent to all active windows.

void SetAppTitle(char* title)

This method is used to set the title of the main application window. This currently only applies to the Microsoft Windows MDI version of V. It is a no-op for the X version. It is still important that you choose a good title for your main window, and set it either with this method, or by providing a good name to the vApp initializer.

void SetValueAll(ItemVal itemId, int Val, ItemSetType what)

This method is similar to vWindow::SetValue, except that the control with the given itemId in ALL currently active windows is set. This is useful to keep control values in different windows in sync. The only difference between vApp::SetValueAll and vWindow::SetValueAll is that the vApp version can be easily called from dialogs as well as windows.

void SetStringAll(ItemVal itemId, char* title)

This method is similar to vWindow::SetString, except that the string with the given itemId in ALL currently active windows is set. This is useful to keep control strings in different windows in sync. The only difference between the vApp::SetStringAll version and the vWindow::SetStringAll version is that the vApp version can be easily called from dialogs as well as windows.

vAppWinInfo *getAppWinInfo(vWindow* win)

This method provides an easy way to retrieve the vAppWinInfo (or more typically, a derived class) object that is associated with a window. By convention, when a window is first created, it and its associated vAppWinInfo object are tracked by NewAppWin. When a user action in a window causes a method in vApp to be invoked, the this of that window is usually sent to the vApp method. You then use that vWindow pointer to call getAppWinInfo to get a pointer to the associated vAppWinInfo object. It will be up to you to determine what information that object has, and how to use it.

MVC

With release 1.21, V adds support for writing MVC (Model View Controller) applications. The MVC paradigm is widely used for object-oriented applications. The basic idea of MVC is that your application consists of some kind of Model for the application. You show various Views of the Model under management of a controller.

How does this translate to V terms? Generally, it is up to you to build your model. Essentially, it will be your data structures and whatever else is needed to implement the core of your app. The controller is usually very closely related to a view of the model. The view and controller will usually be implemented in a vCmdWindow class. You can have different behavior for different views. The power of MVC comes from the ability of a given controller to send a message to all Views of the Model to update themselves as appropriate.

Consider a simple editing program that allows you to edit a data file either in text mode or in hex mode. Your app could have two Views of the Model (your internal representation of the file), one a text view, the other a hex view. Each of these views would be controlled and displayed by individual vCmdWindow classes. If the user makes a change in the text view, then the text view controller would send a message to the hex view to update itself.

V provides two methods to implement MVC, vApp::UpdateAllViews, and [vwindow.htm#UpdateView vWindow::UpdateView]. Your controller sends a message to all other views using UpdateAllViews, and each view receives the message in UpdateView.

void UpdateAllViews(vWindow* sender, int hint, void* pHint)

This method is called by the user whenever a change is made to the model, e.g., the document. This causes vWindow::UpdateView to be called for every open window. The parameters are used to both filter and hint the windows on which actions to take in vWindow::UpdateView.

Generally, you call UpdateAllViews with sender set to this. UpdateAllViews will not call UpdateView for the sender window because typically the change of the model was a result of an interaction with this window. If you want the sender to be called, call with sender zero.

The hints are passed to UpdateView to help define what action the view needs to take. Generally, hint would have a value set to an enum defined in your derived vApp class. These values would hint about which kind of change is made so that only appropriate actions is taken by the appropriate views. The pHint is typically a pointer to the object representing the model.

Tasking

Some applications may have extensive computation requirements. In traditional programming environments, this is usually no problem. However, for GUI based applications, the code cannot simply perform extensive computation in response to some command event (such as a "Begin Computation" menu command). GUIs make a basic assumption that the application will process events relatively quickly. While computation is in process, the application will not receive additional events, and may appear to hang if the computation is too long.

V provides two different approaches to handling compute bound applications. The most straight forward approach is to have the computation periodically call the V method vApp::CheckEvents. CheckEvents will process events, and pass the messages to the appropriate V method. This method may be the most appropriate for applications such as simulations. The second technique is to have the V system call a work procedure periodically to allow some computation to be performed. This technique may be most appropriate for applications that have short computations that should be performed even if the user is not entering commands or interacting with the application. The technique is supported by the WorkSlice method.

CheckEvents()

Most V applications will not need this utility. However, it is possible for some compute bound applications to lock out system response to the events needed to update the screen. If you notice that your application stops responding to input, or fails to consistently update items in your window, then place calls to vApp::CheckEvents() in your code somewhere. You may have to experiment how often you need to call it. It does have some overhead, so you don't want it to slow down your app. But it does need to get called enough so the system can keep up with the screen updates. This function needs no parameters, and returns no value.

EnableWorkSlice(long slice)

For applications that need computations to be performed continuously or periodically, even while the user is not interacting with the program, V provides EnableWorkSlice and WorkSlice. After EnableWorkSlice has been called, V will call the app's WorkSlice method every slice milliseconds. The WorkSlice method of every open vCommandWindow will also be called. Calling EnableWorkSlice with a zero value will stop the calls to the WorkSlice methods.

V uses a standard V [vTimer] object to implement this behavior. Thus, all of the information about actual time intervals and limits on the number of timers discussed in the vTimer description apply to EnableWorkSlice and WorkSlice.

WorkSlice()

When a EnableWorkSlice has been called with a positive value, V calls vApp::WorkSlice at approximately the specified interval (or more likely, the overridden method in your app), as well as the vWindow::WorkSlice method of each open vCommandWindow. Your application can override the appropriate WorkSlice method to perform short, periodic computations. Theses computations should be shorter than the time interval specified for EnableWorkSlice. This may be difficult to ensure since different processors will work at different speeds. One simple way to be sure you don't get multiple calls to the WorkSlice method is to set a static variable on entry to the code. Note that vCommandWindow also has a WorkSlice method. The WorkSlice for the vApp is called first, followed by a call to each open vCommandWindow sequentially in no specific order.

See Also

vWindow, vAppWinInfo