home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l044 / 4.ddi / ONLINE.ZIP / TVISION.DOC < prev    next >
Encoding:
Text File  |  1990-10-23  |  24.7 KB  |  695 lines

  1.  
  2. ======================================================================
  3.                 Additional Turbo Vision Documentation
  4. ======================================================================
  5.  
  6.  
  7. ----------------------------------------------------------------------
  8.                           Table of Contents
  9. ----------------------------------------------------------------------
  10. A. Additional reference material
  11.  
  12.    1. Enhancements to OBJECTS.PAS
  13.       a. New TCollection.AtFree method
  14.       b. Duplicate keys in sorted collections
  15.       c. Changes to TEmsStream.Init to support EMS 3.2
  16.  
  17.    2. Enhancements to DRIVERS.PAS
  18.       a.  MouseReverse variable
  19.  
  20.    3. Enhancements to VIEWS.PAS
  21.       a.  ErrorAttr variable
  22.       b.  TWindow.Close method
  23.       c.  cmListItemSelected constant
  24.       d.  TListViewer.SelectItem method
  25.  
  26.    4. Enhancements to DIALOGS.PAS
  27.       a.  bfBroadcast constant
  28.       b.  TButton.Press method
  29.  
  30.    5. Enhancements to MEMORY.PAS
  31.       a.  bfBroadcast constant
  32.       b.  TButton.Press method
  33.  
  34.    6. Stream RegisterXXXX procedures and ID codes
  35.  
  36. B. Additional explanatory material
  37.    1. Overlaying Turbo Vision applications
  38.    2. Ordering of inherited calls
  39.  
  40. ----------------------------------------------------------------------
  41.  
  42.    This appendix contains additional explanatory and reference
  43.    material about Turbo Vision.
  44.  
  45. 1. Enhancements to OBJECTS.PAS
  46. ------------------------------
  47.  
  48.   TCollection.AtFree method
  49.   -------------------------
  50.  
  51.     procedure TCollection.AtFree(Index: Integer);
  52.  
  53.   Deletes and disposes of the item at the given Index. Equivalent to
  54.  
  55.     Item := At(Index);
  56.     AtDelete(Index);
  57.     FreeItem(Item);
  58.  
  59.   Duplicate keys in sorted collections
  60.   ------------------------------------
  61.  
  62.   TSortedCollection implements sorted collections both with or without
  63.   duplicate keys. The TSortedCollection.Duplicates field controls
  64.   whether duplicates are allowed or not. It defaults to False,
  65.   indicating that duplicate keys are not allowed, but after creating a
  66.   TSortedCollection you can set Duplicates to True to allow elements
  67.   with duplicate keys in the collection.
  68.  
  69.   When Duplicates is True, the Search method returns the index of the
  70.   first item in the collection that has the given key, and the Insert
  71.   method inserts an item before other items (if any) with the same
  72.   key. The IndexOf method uses Search to locate the first item with
  73.   the key given by the Item parameter, and then performs a linear
  74.   search to find the exact Item.
  75.  
  76.   TSortedCollection overrides the Load and Store methods inherited
  77.   from TCollection to also load and store the value of the Duplicates
  78.   field.
  79.  
  80.  
  81.   TEmsStream.Init method
  82.   ----------------------
  83.  
  84.     constructor TEmsStream.Init(MinSize, MaxSize: Longint);
  85.  
  86.   EMS drivers earlier than version 4.0 don't support resizeable
  87.   expanded memory blocks. With a pre-4.0 driver, an EMS stream cannot
  88.   be expanded beyond its initial size once it has been allocated. To
  89.   properly support both older and newer EMS drivers, a TEmsStream's
  90.   Init constructor takes two parameters which specify the minimum and
  91.   maximum size of the initial EMS memory block allocation. Init will
  92.   always allocate at least MinSize bytes.
  93.  
  94.   If the EMS driver version number is greater than or equal to 4.0,
  95.   Init allocates only MinSize bytes of EMS, and then expands the block
  96.   as required by subsequent calls to TEmsStream.Write. MaxSize is
  97.   ignored.
  98.  
  99.   If the driver version number is less than 4.0, Init allocates as
  100.   much expanded memory as is available up to MaxSize bytes, and an
  101.   error will occur if subsequent calls to TEmsStream.Write attempt to
  102.   expand the stream beyond the allocated size.
  103.  
  104.  
  105. 2. Enhancements to DRIVERS.PAS
  106. ------------------------------
  107.  
  108.   MouseReverse variable in Drivers
  109.   -----------------------------------
  110.  
  111.     const MouseReverse: Boolean = False;
  112.  
  113.   Setting MouseReverse to True causes Turbo Vision's event manager to
  114.   reverse the mbLeftButton and mbRightButton flags in the Buttons
  115.   field of TEvent records.
  116.  
  117.  
  118. 3. Enhancements to VIEWS.PAS
  119. ----------------------------
  120.  
  121.   ErrorAttr variable
  122.   ------------------
  123.  
  124.     const ErrorAttr: Byte = $CF;
  125.  
  126.   Contains a video attribute byte used as the error return value of a
  127.   call to TView.GetColor. If TView.GetColor fails to correctly map a
  128.   palette index into a video attribute byte (because of an
  129.   out-of-range index), it returns the value given by ErrorAttr. The
  130.   default ErrorAttr value represents blinking high-intensity white
  131.   characters on a red background. If you see this color combination on
  132.   the screen, it is most likely an indication of a palette mapping
  133.   error.
  134.  
  135.   TWindow.Close method
  136.   --------------------
  137.  
  138.   Calls the TWindow's Valid method with a Command value of cmClose,
  139.   and then, if Valid returns True, closes the window by calling its
  140.   Done method.
  141.  
  142.   cmListItemSelected constant
  143.   ---------------------------
  144.  
  145.   A TListViewer uses the Message function to send an evBroadcast event
  146.   with a Command value of cmListItemSelected to its TView.Owner
  147.   whenever an item in the list viewer is selected (by double-clicking
  148.   on it, or by moving the selection bar to the item and pressing the
  149.   spacebar). The InfoPtr of the event points to the TListViewer
  150.   itself.
  151.  
  152.  
  153.   TListViewer.SelectItem method
  154.   -----------------------------
  155.  
  156.   The default SelectItem method sends a cmListItemSelected broadcast
  157.   to its Owner as follows:
  158.  
  159.     Message(Owner, evBroadcast, cmListItemSelected, @Self);
  160.  
  161.  
  162. 4. Enhancements to DIALOGS.PAS
  163. ------------------------------
  164.  
  165.   bfBroadcast constant in Dialogs
  166.   -------------------------------
  167.  
  168.     const bfBroadcast = $04;
  169.  
  170.   This flag is used in constructing the AFlags bit mask passed to
  171.   TButton.Init. It controls whether TButton objects should generate
  172.   events using the PutEvent method or the Message function. If
  173.   bfBroadcast is clear, a TButton uses PutEvent to geneate an
  174.   evCommand event whenever it is pressed:
  175.  
  176.     E.What := evCommand;
  177.     E.Command := Command;
  178.     E.InfoPtr := @Self;
  179.     PutEvent(E);
  180.  
  181.   If bfBroadcast is set, a TButton uses Message to send an evBroadcast
  182.   message to its Owner whenever it is pressed:
  183.  
  184.     Message(Owner, evBroadcast, Command, @Self);
  185.  
  186.  
  187.   TButton.Press method
  188.   --------------------
  189.  
  190.     procedure TButton.Press; virtual;
  191.  
  192.   This method is called to generate the effect associated with
  193.   "pressing" a TButton object. The default method sends an evBroadcast
  194.   event with a command value of cmRecordHistory to the button's owner
  195.   (causing all THistory objects to record the contents of the
  196.   TInputLine objects they control), and then uses PutEvent or Message
  197.   to generate an event (see description of bfBroadcast flag). You can
  198.   override TButton.Press to change the behaviour of a button when it
  199.   is pressed.
  200.  
  201. 5. Enhancements to MEMORY.PAS
  202. -----------------------------
  203.  
  204.   New SetMemTop procedure
  205.   -----------------------
  206.  
  207.     procedure SetMemTop(MemTop: Pointer);
  208.  
  209.   Sets the top of the application's memory block. The initial memory
  210.   top corresponds to the value stored in the HeapEnd variable.
  211.   SetMemTop is typically used to shrink the application's memory block
  212.   before executing a DOS shell or another program, and to expand the
  213.   memory block afterwards. For an example of how to use SetMemTop, See
  214.   TVDEMO.PAS in the \TP\TVDEMOS directory.
  215.  
  216.  
  217. 6. RegisterXXXX procedures and ID codes
  218. ---------------------------------------
  219.  
  220.   To allow easy interface with streams, the App, ColorSel, Dialogs,
  221.   Editors, Menus, Objects, StdDlg, and Views units each define a
  222.   procedure which registers all object types in the unit using a
  223.   sequence of calls to RegisterType. These registration procedures all
  224.   have names of the form RegisterXXXX where XXXX is the name of the
  225.   containing unit. The types and object ID values registered by the
  226.   RegisterXXXX procedures are show below.
  227.  
  228.     RegisterApp
  229.       TBackground         30
  230.       TDeskTop            31
  231.  
  232.     RegisterColorSel
  233.       TColorSelector      21
  234.       TMonoSelector       22
  235.       TColorDisplay       23
  236.       TColorGroupList     24
  237.       TColorItemList      25
  238.       TColorDialog        26
  239.  
  240.     RegisterDialogs
  241.       TDialog             10
  242.       TInputLine          11
  243.       TButton             12
  244.       TCluster            13
  245.       TRadioButtons       14
  246.       TCheckBoxes         15
  247.       TListBox            16
  248.       TStaticText         17
  249.       TLabel              18
  250.       THistory            19
  251.       TParamText          20
  252.  
  253.     RegisterEditors
  254.       TEditor             70
  255.       TMemo               71
  256.       TFileEditor         72
  257.       TIndicator          73
  258.       TFileWindow         74
  259.  
  260.     RegisterMenus
  261.       TMenuBar            40
  262.       TMenuBox            41
  263.       TStatusLine         42
  264.  
  265.     RegisterObjects
  266.       TCollection         50
  267.       TStringCollection   51
  268.  
  269.     RegisterStdDlg
  270.       TFileInputLine      60
  271.       TFileCollection     61
  272.       TFileList           62
  273.       TFileInfoPane       63
  274.       TFileDialog         64
  275.       TDirCollection      65
  276.       TDirListBox         66
  277.       TChDirDialog        67
  278.  
  279.     RegisterViews
  280.       TView                1
  281.       TFrame               2
  282.       TScrollBar           3
  283.       TScroller            4
  284.       TListViewer          5
  285.       TGroup               6
  286.       TWindow              7
  287.  
  288.   If your application uses stream I/O, you should call the appropriate
  289.   RegisterXXXX procedures in the application's Init method, and in
  290.   addition use RegisterType to register your own types:
  291.  
  292.     type
  293.       TMyApp = object(TApplication)
  294.         constructor Init;
  295.         ...
  296.       end;
  297.  
  298.     constructor TMyApp.Init;
  299.     begin
  300.       RegisterApp;
  301.       RegisterDialogs;
  302.       RegisterMenus;
  303.       RegisterObjects;
  304.       RegisterViews;
  305.       RegisterType(RStringList);
  306.       RegisterType(RMyFirstType);
  307.       RegisterType(RMySecondType);
  308.       TApplication.Init;
  309.       ...
  310.     end;
  311.  
  312.   Notice the explicit call to RegisterType(RStringList) to register
  313.   the TStringList type. The RegisterObjects procedures does not
  314.   register the TStringList and TStrListMaker types, since they have
  315.   the same object type ID (52). Depending on whether your application
  316.   is using or generating string lists, you must manually register
  317.   TStringList or TStrListMaker.
  318.  
  319.   See TVRDEMO.PAS and TVFORMS.PAS in the \TP\TVDEMOS directory for
  320.   examples of applications that perform stream registration.
  321.  
  322.  
  323. ----------------------------------------------------------------------
  324. B. Additional explanatory material
  325.    1. Overlaying Turbo Vision applications
  326.    2. Ordering of inherited calls
  327. ----------------------------------------------------------------------
  328.  
  329. 1. Overlaying Turbo Vision applications
  330. ---------------------------------------
  331.  
  332.   Turbo Vision was designed to work efficiently in an overlaid
  333.   application. All Turbo Vision units can be overlaid, except for the
  334.   Drivers unit, which contains interrupt handlers and other low-level
  335.   system interfaces.
  336.  
  337.   When designing an overlaid Turbo Vision application, carefully
  338.   consider which objects constitute the various "working sets" of your
  339.   application. At any given moment, the user will be interacting with
  340.   a group of objects. Therefore, the code for all of these objects
  341.   need to fit in the overlay pool at the same time to avoid excessive
  342.   disk access. Since Turbo Pascal's overlay manager swaps in entire
  343.   units at a time, do not place unrelated objects in the same overlaid
  344.   unit. If you do, when you use only one of the objects, the code for
  345.   all the others will also be swapped into the overlay pool and will
  346.   take up valuable space. Remember--when a unit is brought into the
  347.   overlay pool, another unit may very well be squeezed out.
  348.  
  349.   Consider an example in which you're designing a special dialog that
  350.   contains some customized controls. Your dialog is derived from
  351.   TDialog and your custom controls are derived from TListViewer and
  352.   TInputLine. Placing all three derived object types in the same unit
  353.   makes sense because they're part of the same working set. However,
  354.   placing other unrelated objects in that unit would require a larger
  355.   overlay pool to hold your working set and therefore may cause disk
  356.   thrashing when you run the program.
  357.  
  358.   Within a Turbo Vision application, the App, Memory, Menus Objects,
  359.   and Views units total about 50 kbytes of code and will almost always
  360.   be part of the current working set. In addition, units containing
  361.   your derived application object and any windows or dialogs with
  362.   which the user is currently interacting will also be part of the
  363.   working set, bringing the typical minimum overlay pool size to about
  364.   64K bytes.
  365.  
  366.   Through experimentation, you can determine the ideal size of the
  367.   overlay pool. In general, the presence of EMS makes code swapping
  368.   much faster and allows you to reduce the size of overlay pool by 25%
  369.   to 35%. Determining the best size of the pool depends on many
  370.   factors, however and generally involves a tradeoff of speed vs.
  371.   capacity. The best approach allows for runtime flexibility with some
  372.   reasonable, established limits. If possible, we recommend that you
  373.   support a command-line parameter or a configuration file to control
  374.   the size of the overlay pool at startup (like the /X command-line
  375.   option for TURBO.EXE).
  376.  
  377.   The following skeleton program presents a typical overlaid Turbo
  378.   Vision application:
  379.  
  380.     program MyProg;
  381.  
  382.     {$F+,O+,S-}
  383.     {$M 8192,65536,655360}
  384.  
  385.     uses Overlay, Drivers, Memory, Objects, Views, Menus, Dialogs,
  386.       HistList, StdDlg, App;
  387.  
  388.     {$O App      }
  389.     {$O Dialogs  }
  390.     {$O HistList }
  391.     {$O Memory   }
  392.     {$O Menus    }
  393.     {$O Objects  }
  394.     {$O StdDlg   }
  395.     {$O Views    }
  396.  
  397.     const
  398.       ExeFileName = 'MYPROG.EXE';     { EXE name for DOS 2.x }
  399.       OvrBufDisk  = 96 * 1024;        { Overlay pool size without EMS }
  400.       OvrBufEMS   = 72 * 1024;        { Overlay pool size with EMS }
  401.  
  402.     type
  403.       TMyApp = object(TApplication)
  404.         constructor Init;
  405.         destructor Done; virtual;
  406.         .
  407.         .
  408.       end;
  409.  
  410.     procedure InitOverlays;
  411.     var
  412.       FileName: string[79];
  413.     begin
  414.       FileName := ParamStr(0);
  415.       if FileName = '' then FileName := ExeFileName;
  416.       OvrInit(FileName);
  417.       if OvrResult <> 0 then
  418.       begin
  419.         PrintStr('Fatal error: Cannot open overlay file.');
  420.         Halt(1);
  421.       end;
  422.       OvrInitEMS;
  423.       if OvrResult = 0 then OvrSetBuf(OvrBufEMS) else
  424.       begin
  425.         OvrSetBuf(OvrBufDisk);
  426.         OvrSetRetry(OvrBufDisk div 2);
  427.       end;
  428.     end;
  429.  
  430.     constructor TMyApp.Init;
  431.     begin
  432.       InitOverlays;
  433.       TApplication.Init;
  434.       .
  435.       .
  436.     end;
  437.  
  438.     destructor TMyApp.Done;
  439.     begin
  440.       .
  441.       .
  442.       TApplication.Done;
  443.     end;
  444.  
  445.     var
  446.       MyApp: TMyApp;
  447.  
  448.     begin
  449.       MyApp.Init;
  450.       MyApp.Run;
  451.       MyApp.Done;
  452.     end.
  453.  
  454.   Notice how the overlay manager is initialized before calling the
  455.   inherited TApplication.Init--this is a requirement since the App
  456.   unit, which contains TApplication, is overlaid. Also notice the use
  457.   of ParamStr(0) to get the name of the .EXE file; that only works
  458.   with DOS version 3.0 or later. In order to support earlier DOS
  459.   versions, a test for a null string combined with the ability to
  460.   supply an .EXE file name is required. Finally, notice that
  461.   OvrSetRetry isn't called if EMS is present, since it generally only
  462.   improves performance when the overlay file is on disk.
  463.  
  464.   The above example assumes that you've used the recommended practice
  465.   of appending the overlay file to the end of .EXE file. This is
  466.   easily done using the DOS COPY command:
  467.  
  468.     REN MYPROG.EXE TEMP.EXE
  469.     COPY/B TEMP.EXE+MYPROG.OVR MYPROG.EXE
  470.  
  471.   See TVRDEMO.PAS in the \TP\TVDEMOS directory for an example of an
  472.   overlaid Turbo Vision application. And always remember to place a
  473.   {$F+,O+} directive at the beginning of all overlaid units.
  474.  
  475.   For further information on Turbo Pascal's overlay manager, please
  476.   refer to Chapter 13 in the Programmer's Guide.
  477.  
  478.  
  479. 2. Ordering of inherited calls
  480. ------------------------------
  481.  
  482.   Turbo Vision is designed so that you can extend it to suit your
  483.   application's specific needs by deriving new descendants from
  484.   existing Turbo Vision objects. Sometimes, your new object will want
  485.   to completely replace the inherited behavior for a given method. For
  486.   example, when TInputLine is derived from TView, TInputLine.Draw does
  487.   not call its inherited method, TView.Draw. That's because TView.Draw
  488.   simply creates an empty rectangle. Instead, TInputLine overrides the
  489.   inherited Draw and defines a new one:
  490.  
  491.     procedure TInputLine.Draw;
  492.      ...
  493.     begin
  494.       { Insert code to draw an input line here }
  495.     end;
  496.  
  497.   In fact, calling TView.Draw would cause an unpleasant flicker on the
  498.   screen when first TView cleared the rectangle, and then TInputLine
  499.   filled it in. Methods like Draw are an exception, though.
  500.   Programming effectively with Turbo Vision involves making lots of
  501.   inherited method calls. For each method you're overriding, you must
  502.   know which to do first: Execute the code that you're adding? Or
  503.   first call the inherited method and then execute your new code?
  504.   Moreover, as you've just seen with the Draw method, sometimes you
  505.   don't call your inherited method at all. Doing the right thing in
  506.   the right order, of course, depends on where your new object falls
  507.   in the Turbo Vision hierarchy and which method you're overriding.
  508.   The rules for inherited call ordering break into 3 categories
  509.  
  510.   1)  Constructors. Call the inherited method first.
  511.  
  512.         procedure MyObject.Init(...);
  513.         begin
  514.           { Call inherited Init first }
  515.           { Insert code to init MyObject }
  516.         end;
  517.  
  518.   2)  Destructors. Call the inherited method last.
  519.  
  520.         procedure MyObject.Done;
  521.         begin
  522.           { Insert code to cleanup MyObject }
  523.           { Call inherited Done last }
  524.         end;
  525.  
  526.   3)  All other methods: It depends. See below for an explanation.
  527.  
  528.   Overriding Init and Load: The Call First Rule
  529.   ---------------------------------------------
  530.   You should always call your inherited constructor first and then
  531.   initialize any new fields your descendent object defines. This
  532.   advice applies to Init and Load constructors equally
  533.  
  534.     type
  535.       MyObject = object(TWindow)
  536.         Value: Word;
  537.         Ok: Boolean;
  538.         constructor Init(var Bounds: TRect; ATitle: TTitleStr;
  539.           AValue: Word; AOk: Boolean);
  540.       end;
  541.  
  542.     constructor MyObject.Init(var Bounds: TRect; ATitle: TTitleStr;
  543.       AValue: Word; AOk: Boolean);
  544.     begin
  545.       TWindow.Init(Bounds, ATitle, wnNoNumber);
  546.       Value := 16;
  547.       Ok := True;
  548.     end;
  549.  
  550.   Here, MyObject calls its inherited Init method, TWindow.Init, to
  551.   perform initialization, first. Then MyObject puts meaningful values
  552.   into Value and Ok. If you were to reverse the order of these steps,
  553.   you'd be in for an unpleasant surprise: Value would be zero and Ok
  554.   would be False! That's because TWindow follows the Init convention
  555.   and calls its inherited method, TGroup.Init. TGroup.Init calls
  556.   TView.Init; which--finally--calls TObject.Init, the ultimate
  557.   ancestor to all Turbo Vision objects. TObject.Init zeros ALL the
  558.   fields in MyObject, including Value and Ok.
  559.  
  560.   Your Init and Load methods can rely on this and refrain from zeroing
  561.   new fields--as long as you're deriving an object from some TView
  562.   descendant.
  563.  
  564.   The Exception
  565.   -------------
  566.   Having said "always call the inherited constructor first", it's not
  567.   always true. When working with non-view objects like TCollection or
  568.   TStream descendants, you don't HAVE to call your inherited Init or
  569.   Load first. But you should, unless there is some compelling reason
  570.   to break the rule. And there might be, as in the following case when
  571.   an inherited constructor includes a call to a virtual method which
  572.   has been overridden. TCollection.Load relies on the virtual method
  573.   GetItem to get a collection item from the stream
  574.  
  575.     constructor TCollection.Load(var S: TStream);
  576.     begin
  577.       ...
  578.       for I := 0 to Count - 1 do AtPut(I, GetItem(S));
  579.     end;
  580.  
  581.   Since GetItem is virtual, you may have overridden it and your
  582.   GetItem may rely on your descendent object's Load method to
  583.   initialize a field before GetItem is called. In this case, you'd
  584.   want your new Load method to read the field value first, then call
  585.   TCollection.Load, which would end up "calling back" to your GetItem.
  586.   Here's a partial implementation of a collection of binary data (not
  587.   objects). The size of a data item is fixed for the entire collection
  588.   and held in the new field, ItemSize
  589.  
  590.     type
  591.       PDataCollection = ^TDataCollection;
  592.       TDataCollection = object(TStringCollection)
  593.         ItemSize: Word;
  594.         KeyType: KeyTypes;
  595.         constructor Init(ALimit, ADelta, AnItemSize: Integer);
  596.         constructor Load(var S: TStream);
  597.         function Compare(Key1, Key2: Pointer): Integer; virtual;
  598.         procedure FreeItem(Item: Pointer); virtual;
  599.         function GetItem(var S: TStream): Pointer; virtual;
  600.         procedure PutItem(var S: TStream; Item: Pointer); virtual;
  601.         procedure Store(var S: TStream); virtual;
  602.       end;
  603.  
  604.     ...
  605.  
  606.     constructor TDataCollection.Load(var S: TStream);
  607.     begin
  608.       S.Read(ItemSize, SizeOf(ItemSize));
  609.       TStringCollection.Load(S);
  610.     end;
  611.  
  612.     function TDataCollection.GetItem(var S: TStream): Pointer;
  613.     var Item: Pointer;
  614.     begin
  615.       GetMem(Item, ItemSize);
  616.       S.Read(Item^, ItemSize);
  617.       GetItem := Item;
  618.     end;
  619.  
  620.     ...
  621.  
  622.   Load first reads the ItemSize off the stream, then it calls
  623.   TSTringCollection.Load, which "calls back" to GetItem. Now GetItem
  624.   knows how big the item it's supposed to load is and can allocate
  625.   heap and read data correctly. That's why the "call inherited first"
  626.   applies to TView descendants all the time and to all other objects
  627.   unless there's a compelling reason. And of course, Load and Store go
  628.   hand-in-hand, so in this example, Store would write data to the
  629.   stream in the same order as Load reads it. This code is extracted
  630.   from the DATACOLL.PAS unit in the \TP\TVDEMOS directory.
  631.  
  632.   Destructors: call them last
  633.   ---------------------------
  634.   A destructor's job is to undo the constructor's handiwork in reverse
  635.   order. Therefore, a destructor should always free its own dynamic
  636.   memory and then call its inherited destructor to do the same.
  637.  
  638.  
  639.   All other methods: it depends
  640.   -----------------------------
  641.   You saw how TInputLine doesn't call its inherited Draw method. If it
  642.   did, TView.Draw would have to be called first or else it would
  643.   obliterate any writing done by TInputLine.Draw. For the remaining
  644.   Turbo Vision methods, whether to make an inherited call or not--and
  645.   in what order--depends on which method you're overriding. In
  646.   general, call the inherited method first. We've covered the most
  647.   common methods to override: Init, Done, Draw, Load, and Store. Now
  648.   consider HandleEvent. Here's a skeleton of a descendent object's
  649.   HandleEvent method
  650.  
  651.     procedure MyObject.HandleEvent(var Event: TEvent);
  652.     begin
  653.       { Insert code to change inherited behavior }
  654.       { Call inherited HandleEvent }
  655.       { Insert code to add additional behavior }
  656.     end;
  657.  
  658.   First, code that will CHANGE the inherited behavior is executed.
  659.   Then the inherited call is made. Finally, the code that will EXTEND
  660.   the inherited behavior is added.
  661.  
  662.   If you want to change the way the inherited method behaves or filter
  663.   out events, then put this code ahead of the inherited call. Most
  664.   Turbo Vision views call their inherited HandleEvent and then add
  665.   code to handle new events
  666.  
  667.     procedure TDialog.HandleEvent(var Event: TEvent);
  668.     begin
  669.       TWindow.HandleEvent(Event);
  670.       case Event.What of
  671.         evKeyDown:
  672.             ...
  673.         evCommand:
  674.             ...
  675.       end;
  676.     end;
  677.  
  678.   TDialog's HandleEvent manages all keyboard and mouse events,
  679.   including tabs. But what if you need to define a new dialog that
  680.   ignores tabs? Since you want to change your inherited method's
  681.   behavior (the handling of tabs) you'll put this tab-eating code
  682.   BEFORE the call to TDialog.HandleEvent
  683.  
  684.     procedure TNoTabsDialog.HandleEvent(var Event: TEvent);
  685.     begin
  686.       if (Event.What = evKeyDown) then
  687.         if (Event.KeyCode = kbTab) or (Event.KeyCode = kbShiftTab) then
  688.           ClearEvent(Event);
  689.       TDialog.HandleEvent(Event);
  690.     end;
  691.  
  692.   That's it. Your TNoTabsDialog will throw away the tabs before
  693.   TDialog.HandleEvent can ever see them and the tab key will not move
  694.   from control to control when using your dialog.
  695.