Retro video games delivered to your door every month!
Click above to get retro games delivered to your door ever month!
X-Hacker.org- The Guide to Clip-4-Win version 3.0 - http://www.X-Hacker.org [<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
  
  The form was designed with the working name "UsersForm" and is
  implemented as "UsersDialog".
  
  The intent of the UsersDialog class during initialisation is
  to open the USERS file, copy (scatter) the fields to instance
  variables (to buffer changes), and initialise user interface
  objects.
  
  In the code, you need to pick the appropriate combination of
  the Init() and OnInitDialog() methods to get the dialog on
  the screen.
  
  The explanations below correspond to the resource and non-
  resource (dynamic dialog) versions of this application; the
  resource version is shorter and appears first.
  
  A resource dialog ends up with a description of its appearance
  stored as a template in your EXE or a DLL.  All you need to do
  in Init() is provide the dialog's ID (a number or string).
  You don't need to change the inherited Init() method in this
  example.  If you wanted to pass some more parameters, e.g. a
  file name, you'd re-define the Init() method, and probably
  assign the extra parameters to instance variables.
  
  The dialog support code reads and interprets the dialog
  resource.  It creates the dialog and its controls, then the
  OnInitDialog() method is invoked, so you can put the rest of
  your initialisation code in this method of your sub-class.
  The main code needed for a resource dialog is to create
  (instantiate) objects needed during the life of the dialog -
  especially objects corresponding to controls.
  
  To open the USERS file, the method starts:
  
       METHOD OnInitDialog() CLASS UsersDialog
  
       ::oUsers = WTable{self, "users"}
       (::oUsers:Area) -> ( dbGoTop() )
  
       ::Scatter()        // fetch fields
  
  (The Scatter() method copies the fields to the instance
  variables cUserID, cUserName, cDept, cPhone and cExt.)
  
  This code to open USERS could be in the Init() method, but as
  this sub-class didn't need its own Init() method it was
  easier to put the above code into OnInitDialog().
  
  The method continues by creating the objects for the data
  input fields, saving the objects so they can be told when
  record movement occurs.
  
       @ Id IDD_USERID    Obj ::oUserID    Get ::cUserID
       @ Id IDD_USERNAME  Obj ::oUserName  Get ::cUserName
       @ Id IDD_DEPT      Obj ::oDept      Get ::cDept
       @ Id IDD_PHONE     Obj ::oPhone     Get ::cPhone
       @ Id IDD_EXT       Obj ::oExt       Get ::cExt   Picture "9999"
  
  Next are the buttons, noting that Ok() and Cancel() will
  automatically be invoked for the Ok and Cancel buttons -
  because the dialog resource uses the standard ID's for these
  buttons (IDOK and IDCANCEL).  To associate button pushes with
  the Next(), Previous() and Save() methods:
  
       @ Id IDD_NEXT  PushButton Next
       @ Id IDD_PREV  PushButton Previous
       @ Id IDD_SAVE  PushButton Save
  
  
  Finally, use the inherited behaviour:
  
       return super:OnInitDialog()
  
  
  The actions during the dialog's existence are discussed shortly,
  but first let's turn to the dynamic (non-resource) dialog.
  
  This time there's no pre-existing dialog template (resource),
  so it has to be created by the application.  Ultimately this
  means calling the CreateDialog() and AppendDialog()
  functions, but there are some #commands to do this which
  conveniently create the user interface objects at the same
  time.  This isn't faster, but it does get all the code into
  one place.
  
  You need to create the dynamic dialog information before or
  during the Init() method, because the dialog support code
  can't guess what you want.  You make this information
  available to the dialog's Create() method, which will hand it
  on to the dialog support code in Windows and Clip-4-Win.  This
  way, the dialog will be created, OnInitDialog() will be
  invoked, and so on.
  
  The Init() method is going to be very like the resource
  dialog's OnInitDialog(), but with the extra complications of
  creating the information about the dialog and controls.  The
  method starts by using the inherited initialisation, but stops
  the Create() method being called - you can't do that until
  later.
  
       METHOD Init(oParent) CLASS UsersDialog
       super:Init(oParent, , .f.)
  
       ::oUsers = WTable{self, "users"}
       (::oUsers:Area) -> ( dbGoTop() )
  
       ::Scatter()        // fetch fields
  
  The dialog information itself is created, showing off a little
  by specifying the font details:
  
       INIT DIALOG self                                  ;
            TITLE "User Details"                         ;
            STYLE DS_MODALFRAME + WS_POPUP + WS_VISIBLE  ;
                   + WS_CAPTION + WS_SYSMENU             ;
            AT 20,20 SIZE 183,127                        ;
            POINTSIZE nPointSize  FONTNAME cFontName
  
  The resource dialog made adding input fields very short - all
  the prompts were part of the resource.  Creating them by hand
  isn't too bad, although deciding position and size is a chore.
  The example uses the same values as the resource, but you'd
  probably stick to multiples of 5 or 10, adjusting them only
  where necessary.
  
  @ ID IDD_TUSERID  SAY  "User &ID:"                  AT 7,2   SIZE 50,8
  @ Id IDD_USERID   Obj ::oUserID      Get ::cUserID  AT 7,13 SIZE 115,13
  // . . .
  @ ID IDD_T_EXT    SAY  "&Extension:"                AT 7,100 SIZE 50,8
  @ Id IDD_EXT      Obj ::oExt         Get ::cExt  Picture "9999"    ;
                                                      AT 7,109  SIZE 115,13
  
  The buttons are similar.  The Ok and Cancel buttons need
  creating, but as before there's no need to list the Ok() and
  Cancel() methods (although you can):
  
  @ ID IDOK      BUTTON       TITLE "&Ok"    AT 132,13  SIZE 37,12
  // . . .
  @ ID IDD_SAVE  BUTTON Save  TITLE "&Save"  AT 132,109 SIZE 37,12
  
  The last thing is to invoke Create():
  
       ::Create()
  
       return self
  
  This can be shortened to    return ::Create()    if you like.
  
  
  The remaining parts of both resource and dynamic versions are
  the same and unremarkable, except for the ReDo() method in
  UsersDialog.
  
  The ReDo() method in UsersDialog exists to co-operate with
  the ReDo() service provided by the WTable class.  You don't
  have to use this facility, and it's not triggered
  automatically.  In the examples, the Save() method invokes
  the WTable object's ReDo(), passing it the record number as a
  parameter.  You can pass anything at all as a parameter,
  because if WTable passes it on it does so without examining
  it.  What WTable does if it's ReDo() is invoked is to find
  out if the file is open more than once, and if so it informs
  the other objects using the file that ReDo() has been
  invoked.  It does this by invoking the ReDo() method in each
  of the owners (parents) of the other WTable objects with the
  same file open.  The parameter you passed is handed on
  unchanged.
  
  This mechanism provides a way to propagate information to all
  open instances of a file.  Typically you use it when an update
  occurs, to get the other open instances to re-read data if
  necessary.
  
  This is what is happening in the example: you can view the
  same record more than once, change one, click on Save, and
  you'll see the others are updated with the new data.
  
  This is a completely general-purpose mechanism; how you use
  it, if at all, is up to you.  The main drawback is that it
  complicated WTable a little, forcing it to keep track of the
  details of what's open.  The overhead is low, though,
  especially for something so useful.
  
  
  

Online resources provided by: http://www.X-Hacker.org --- NG 2 HTML conversion by Dave Pearson