home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / DELPHI16 / TECHINFO / DELPHI / FAQS / DELSEC05.FAQ < prev    next >
Encoding:
Text File  |  1995-08-24  |  39.1 KB  |  972 lines

  1. SECTION 5 - Delphi VCL
  2.  
  3. This document contains information that is most often provided
  4. to users of this section.  There is a listing of common
  5. Technical Information Documents that can be downloaded from 
  6. the libraries, and a listing of the most frequently asked
  7. questions and their answers.
  8.  
  9. TI1171  Bug Report Form
  10. TI2711  How to Circumvent the "Index not found" Exception
  11. TI2776  List of Delphi books from Third-Party Publishers
  12. TI2779  Delphi Client/Server and PowerBuilder Compared
  13. TI2781  Step by Step Configuration of an ODBC Driver
  14. TI2841  Delphi Consultants and Training Centers
  15.  
  16. Delphi FTP and WWW sites on Internet:
  17.  
  18.   ftp.borland.com
  19.   ftp.netcom.com   /pub/ic/ice-floe.
  20.  
  21.   http://www.Borland.com
  22.   http://www.cybernetics.net/users/bstowers/delphi-bugs.html
  23.   http://www.coriolis.com/coriolis/whatsnew/delphi.htm
  24.  
  25. Zip files related to VCL components:
  26.  
  27. VCLPATCH.ZIP   Patch for the Visual Component Library source.
  28. DELCSPAT.ZIP   Patch for Delphi Client Server.
  29. DELPATCH.ZIP   Patch for Delphi
  30.  
  31. Questions and answers:
  32.  
  33. ------------------------------------------------------------------------
  34.  
  35. Q: "How can VCL components be created on the fly at run-time?"
  36.  
  37. A: The following code will create a modal password form at runtime.
  38.    The TPasswordForm type is a TForm descendent class defined either
  39.    in the current unit or in a separate unit referenced by the current
  40.    unit's uses clause.
  41.  
  42.    with TPasswordForm.Create(Application) do
  43.    begin                               ( i.e TForm1, TPasswordForm etc. } 
  44.       ShowModal;                       { Display form as a modal window }
  45.       Free;                            { Free the form when it is closed }
  46.    end;      
  47.  
  48.    The following are the general steps to add a component to a form at 
  49.    run-time:  
  50.  
  51.    1. Declare an instance variable of the component type that you wish to
  52.       create {i.e. TButton }. Note: instance variables are used to point
  53.       to an actual instance of an object. They are not objects themselves.
  54.    2. Use the component's Create constructor to create an instance
  55.       of the component and assign the instance to the instance 
  56.       variable declared in step 1.  All components' Create constructors 
  57.       take a parameter - the component's owner.  Except in special 
  58.       circumstances, you should always pass the form as the owner 
  59.       parameter of the component's Create constructor.
  60.    3. Assign a parent to the component's Parent property (i.e. Form1,
  61.       Panel1, etc).  The Parent determines where the component will be 
  62.       displayed, and how the component's Top and Left coordinates are 
  63.       interpreted. To place a component in a groupbox, set the 
  64.       component's Parent property to the groupbox.  For a component
  65.       to be visible, it must have a parent to display itself within.
  66.    4. Set any other properties that are necessary  (i.e. Width, Height).
  67.    5. Finally, make the component appear on the form by setting the 
  68.       component's Visible property to True. 
  69.    6. If you created the component with an owner, you
  70.       don't need to do anything to free the component - it will be freed
  71.       when the owner is destroyed.  If you did not give the component an
  72.       owner when you created it, you are responsible for making sure
  73.       the component is freed when it is no longer needed.
  74.       The following demonstrates how to add a TButton component to the 
  75.       current form at run-time:  
  76.  
  77.    var
  78.      TempButton : TButton;  { This is only a pointer to a TButton }    
  79.    begin 
  80.      TempButton := TButton.Create(Self); { Self refers to the form }
  81.      TempButton.Parent := Self;          { Must assign the Parent } 
  82.      TempButton.Caption := 'Run-time';   { Assign properties now }
  83.      TempButton.Visible := True;         { Show to button }
  84.    end; 
  85.  
  86.    Since the button was created with an owner, it will be freed 
  87.    automatically when its owner, the form, is freed.     
  88.  
  89. ------------------------------------------------------------------------
  90.  
  91. Q: "How can the event handler of a popup menu item determine which 
  92.    component was right-clicked upon to activate that menu?
  93.  
  94. A: Use the PopupMenu.PopupComponent property 
  95.    to determine what control the menu was activated for.
  96.  
  97.    procedure TForm1.PopupItem1Click(Sender: TObject);
  98.    begin
  99.      Label1.Caption := PopupMenu1.PopupComponent.ClassName;
  100.    end;
  101.  
  102.    The form's ActiveControl property can also be used, however, 
  103.    the active control may not necessarily be the control that
  104.    caused the popup menu to appear. 
  105.  
  106. ------------------------------------------------------------------------
  107.  
  108. Q: "What are the capacity limits of the standard Delphi controls?"
  109.  
  110. A: Any component that uses a TList to store information has an upper
  111.    bound of 16368 items. For example, a TTabControl can contain up to
  112.    16368 tabs and the Delphi Component Palette can contain up to
  113.    16368 palette pages.
  114.  
  115.    Many of the Delphi standard components are wrappers around standard
  116.    Windows controls.  Windows 3.1 imposes its own limits on these 
  117.    components.  For example: a TComboBox or TListbox can hold up to
  118.    5440 items and TMemo or TEdit (and related components) can hold up 
  119.    to 32k of text.
  120.  
  121.    Windows 3.1 resource space imposes a limit of 570 pages in a 
  122.    TNoteBook component. (It's difficult to get more than 500 window 
  123.    handles in any Windows application.)
  124.  
  125.    Note 1: Exceeding these limits will raise exceptions or cause Windows
  126.    to behave strangely.
  127.  
  128.    Note 2: Many of the Windows-based capacity limits are much higher 
  129.    in the 16-bit WOW box of Windows NT and in Windows 95.  In future
  130.    32 bit releases of Delphi, virtually all of these limits will 
  131.    disappear.
  132.  
  133. ------------------------------------------------------------------------
  134.  
  135. Q: "How can I determine the Length in pixels of a string after a
  136.    specific font has been aplied to it?"
  137.  
  138. A: Use the Canvas methods TextHeight and TextWidth to
  139.    determine the text height and width of a string in
  140.    pixels.  Be sure to assign the font into the Canvas before
  141.    drawing or taking measurements.
  142.  
  143.    All visual components have a Canvas property, but
  144.    usually this property is protected so that only direct descendents
  145.    can draw on the Canvas.  Since you write much of your code
  146.    inside methods of a TForm descendent, you always have access to 
  147.    your form's inherited Canvas property.  The TPaintBox component
  148.    makes its Canvas property public so that you can draw on the
  149.    component from OnPaint event methods in the form.
  150.  
  151.    If a component doesn't have a Canvas property you can use the
  152.    following function to get the text width based on the font passed.
  153.  
  154.    function GetTextWidth(CanvasOwner: TForm; Text : String;
  155.                          TextFont :  TFont): Integer;
  156.    var
  157.      OldFont : TFont;
  158.    begin
  159.      OldFont := TFont.Create;
  160.      try
  161.        OldFont.Assign( CanvasOWner.Font );
  162.        CanvasOWner.Font.Assign( TextFont );
  163.        Result := CanvasOwner.Canvas.TextWidth(Text);
  164.        CanvasOWner.Font.Assign( OldFont );  
  165.      finally
  166.        OldFont.Free;
  167.      end;
  168.    end;
  169.  
  170. ------------------------------------------------------------------------
  171.  
  172. Q: "Why do some visual components like TPanel and TEdit not have a
  173.    Canvas property?"
  174.  
  175. A: All descendents of TCustomControl have a Canvas property, however,
  176.    most are protected to prevent 'outsiders' from drawing on the
  177.    component.  Descendents of a component can always access the 
  178.    protected properties they inherit from the component 
  179.    (such as Canvas), but users of the component cannot.
  180.  
  181.    type
  182.      TCanvasPanel = class(TPanel)
  183.      public
  184.        property Canvas;
  185.      end;
  186.  
  187.    If you want to draw on a component that doesn't have a public 
  188.    canvas property, consider using a different component that was 
  189.    intended for arbitrary drawing (TPaintBox), or layer components to 
  190.    achieve the desired result (client-align a TPaintBox inside a TPanel
  191.    to get a bevelled, drawable area).
  192.  
  193. ------------------------------------------------------------------------
  194.  
  195. Q: "How can I get a horizontal scrollbar on a list box?"
  196.  
  197. A: Send a LB_SetHorizontalExtent message to the listbox's window handle.
  198.    For example, the message could be sent in the form's OnCreate:
  199.  
  200.    procedure TForm1.FormCreate(Sender: TObject);
  201.    begin
  202.      SendMessage(Listbox1.Handle, LB_SetHorizontalExtent, 1000, Longint(0));
  203.    end;
  204.  
  205. ------------------------------------------------------------------------
  206.  
  207. Q: "Does Delphi have a component that supports serial communications?"
  208.  
  209. A: No. However, there are serial communications libraries (and soon 
  210.    Delphi components) for Delphi available from third party vendors
  211.    such as TurboPower, SaxComm, and and others.
  212.  
  213. ------------------------------------------------------------------------
  214.  
  215. Q: "How can the tab stops be set in a TMemo control?"
  216.  
  217. A: To change the tab stops for a multiline edit control
  218.    (i.e. a TMemo) send the EM_SetTabStops message to the
  219.    component.  The Tabs array indicates where the tab stops 
  220.    will be located.  Since the WParam parameter to 
  221.    SendMessage is 1, then all tab stops will be set to the 
  222.    value passed in the Tabs array.  Remember to set the
  223.    WantTabs property of TMemo to True to enable the tabs.
  224.  
  225.    procedure TForm1.FormCreate( Sender : TObject );
  226.    const
  227.      TabInc : LongInt = 10;
  228.    begin
  229.      SendMessage( Memo1.Handle, EM_SetTabStops, 1, Longint( @TabInc ) );
  230.    end;
  231.  
  232. ------------------------------------------------------------------------
  233.  
  234. Q: "Where is the best place to open a splash screen on program start up?"
  235.  
  236. A: The best place to open a splash screen is in the project source 
  237.    file after the first Application.FormCreate and before the
  238.    Application.Run.  This is accomplished by creating a form on
  239.    the fly and then displaying it before the application is actual
  240.    opened.
  241.  
  242.    program Project1;
  243.  
  244.    uses Forms, Unit1 in 'UNIT1.PAS' {Form1}, Splash;
  245.  
  246.    {$R *.RES}
  247.    var
  248.      SplashScreen : TSplashScreen;  {in the Splash unit}
  249.    begin
  250.      Application.CreateForm(TForm1, Form1);
  251.      SplashScreen := TSplashScreen.Create(Application);
  252.      try
  253.        SplashScreen.Show;
  254.        SplashScreen.Update; {Process any pending Windows paint messages}
  255.        {
  256.         do other CreatForms or any other processing before the
  257.         application is to be opened.  If the start up processing is
  258.         going to take a long time you may want to run
  259.         Application.ProcessMessages periodically to allow Windows
  260.         to respond to Windows messages.
  261.        }
  262.      finally               {Make sure the splash screen gets released}
  263.        SplashScreen.Free; 
  264.      end;   
  265.      Application.Run;
  266.    end.
  267.  
  268. ------------------------------------------------------------------------
  269.  
  270. Q: "Why does the OnExit event of a TEdit component not execute when 
  271.    the user clicks on a speed button?  Is there a way to make a 
  272.    an OnExit event execute when a speed button is pressed?"
  273.  
  274. A: A speed button never actually gets focus, so the active
  275.    control never loses its focus, consequently the active
  276.    control's OnExit event never occurs. 
  277.  
  278.    One way to execute the active control's OnExit event is to
  279.    explicitly call it in the OnClick event of the speedbutton. 
  280.    For example:
  281.  
  282.    procedure TForm1.SpeedButton1Click(Sender: TObject);
  283.    begin
  284.      If ActiveControl is TEdit then 
  285.         (ActiveControl as TEdit).OnExit(ActiveControl);
  286.    end;
  287.  
  288. ------------------------------------------------------------------------
  289.   
  290. Q: "When I open the child windows at run-time each one is 
  291.    positioned slightly down and to the right of the previous
  292.    window.  My problem is that if I then close some of the child 
  293.    windows and then open a new one, the new one is placed 
  294.    down and to the right of where the last child window was 
  295.    before I closed it, even though it is no longer there! 
  296.    Is this as designed?"  
  297.  
  298. A: That's how MDI windows works. VCL doesn't override Windows
  299.    default behavior in this situation.
  300.  
  301.    Untested suggestion: In the FormCreate procedure try 
  302.    setting the Top, Left, Width & Height properties to the values
  303.    that you require.  The MDI child form's FormCreate is called 
  304.    before the window is displayed.
  305.  
  306. ------------------------------------------------------------------------
  307.  
  308. Q: "Why can't my program find any of the resources that I put in a .RES 
  309.    file if that .RES file is the same name as my form's unit name?"
  310.  
  311. A: If the name of an included .RES file is the same as the name
  312.    of a .DPR file Delphi wll overwrite it with it's own .RES file.  
  313.    In addition, the project RES file is for the Delphi project
  314.    manager only; don't edit or add resources to this RES file.  
  315.  
  316. ------------------------------------------------------------------------
  317.  
  318. Q: "How can you do scrolling functions in a TForm component using 
  319.    keyboard commands?  For example, scrolling the form up and down 
  320.    with the PgUp and PgDn keys.  
  321.  
  322. A: Form scrolling is accomplished by modifying the VertScrollbar 
  323.    or HorzScrollbar Postion properties of the form.  The following
  324.    code demonstrates how to do this:
  325.  
  326.    procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  327.    Shift: TShiftState);
  328.    const
  329.      PageDelta = 10;
  330.    begin
  331.      With VertScrollbar do
  332.        if Key = VK_NEXT then  Position := Position+PageDelta
  333.        else if Key = VK_PRIOR then Position := Position-PageDelta;
  334.    end;
  335.  
  336.    Note: This may not work well if the active control uses PgUp & PgDn,
  337.    too, like a TMemo.
  338.  
  339. ------------------------------------------------------------------------
  340.  
  341. Q: "Is there a way to fill a TListbox or TMemo in one shot?"
  342.  
  343. A: To fill multiple lines of a TListbox or TMemo component the SetText
  344.    method can be used.  The null terminated string passed to the 
  345.    SetText method is a concatination of each line of text delimeted
  346.    by a carriage return character #13 in between.  For example, 
  347.    the follow statement:
  348.  
  349.    Listbox1.Items.SetText('aaaaa'#13'bbbbb'#13'ccccc')
  350.  
  351.    will display the following in a listbox window:
  352.  
  353.    aaaaa
  354.    bbbbb
  355.    ccccc
  356.  
  357.    Note: The preferred method of filling a listbox or memo is with the
  358.    Add method of their Items and Lines properties, respectfully.
  359.  
  360. ------------------------------------------------------------------------
  361.  
  362. Q: "Is it possible to create something like the Control Array in Visual
  363.    Basic?   For example, I want a group of buttons with a common event
  364.    handler whereby the event handler picks up an integer value for the
  365.    particular button. In Visual Basic this would be done via the
  366.    Control Array index."
  367.  
  368. A: One way do to this is to set the Tag field for each button to a
  369.    different number and then create a common OnClick event handler
  370.    that looks at the Sender's Tag field.  Assign the same OnClick
  371.    event handler to all the buttons in the group.  And then the
  372.    OnClick event handler would look something like this:
  373.  
  374.    procedure TForm1.Button1Click(Sender: TObject); var cap: string;
  375.    begin
  376.      case TButton(sender).Tag of
  377.        1: ShowMessage('1st Button Pressed');
  378.        2: ShowMessage('2nd Button Pressed');
  379.        3: ShowMessage('3rd Button Pressed');
  380.      end;
  381.    end;
  382.  
  383. ------------------------------------------------------------------------
  384.  
  385. Q: "How can a new component be added to a page of a
  386.    TTabbedNoteBook at run time?  How do I determine 
  387.    what the parent will be for the new component?"
  388.  
  389. A: To add a component to a TabbedNotebook page at run-time a
  390.    pointer to the desired page must be assigned to the new
  391.    component's Parent property before it can be shown.  The way to 
  392.    access all the pages of a TTabbedNotebook at run-time is with 
  393.    the Objects array property of the TabbedNotebook's Pages property.
  394.    In other words, the page components are stored as objects attached
  395.    to the page names in the Pages string list property.  The follow
  396.    demonstrates the creation of a button on the second page of
  397.    TabbedNotebook1:
  398.  
  399.    var 
  400.      NewButton : TButton;
  401.    begin
  402.      NewButton := TButton.Create(Self);
  403.      NewButton.Parent := TWinControl(TabbedNotebook1.Pages.Objects[1])
  404.      ...               
  405.      
  406.    This is how a TNotebook page would be used as a parent to a newly 
  407.    created component on that page: 
  408.     
  409.    NewButton.Parent := TWinControl(Notebook1.Pages.Objects[1])
  410.  
  411.    This is how a TTabSet tab page would be used as a parent to a
  412.    newly created component on that tab page: 
  413.     
  414.    NewButton.Parent := TWinControl(TabSet1.Tabs.Objects[1])
  415.  
  416. ------------------------------------------------------------------------
  417.  
  418. Q: "Are there any vertical ( side of the page ) tab components
  419.    available, commercial, shareware or freeware."
  420.  
  421. A: TurboPower's Orpheus product will support this. GO TURBOPOWER
  422.    for more information.
  423.  
  424. ------------------------------------------------------------------------
  425.  
  426. Q: "Is there an easy way to get CopyToClipboard, CutToClipboard etc. 
  427.    to know to use the TEdit that has focus?  
  428.  
  429. A: Simply check to see if the ActiveControl is of type TEdit and then 
  430.    do the desired cut, copy or paste operation. For example:
  431.  
  432.    if (ActiveControl is TEdit) then
  433.       TEdit(ActiveControl).CopyToClipboard;     
  434.  
  435. ------------------------------------------------------------------------
  436.  
  437. Q: "Does a TDBGrid component have an OnMouseDown, OnMouseUp and 
  438.    OnMouseMove events?"
  439.  
  440. A: The events are there, but they aren't published.  You could 
  441.    create a simple decendant of TDBGrid and publish them.
  442.  
  443. ------------------------------------------------------------------------
  444.  
  445. Q: "Does Delphi grab system resources when displaying and closing
  446.    modal dialogs?  For example, the following code decreases the
  447.    system resources every time it is used to show a modal dialog."
  448.  
  449.    ModalForm1 := TModalForm1.Create(Self);
  450.    ModalForm1.ShowModal;
  451.  
  452. A: Without an OnClose event handler that sets Action parameter to
  453.    caFree, your code is creating a new form with each call to
  454.    TModalForm1.Create(Self), but the previously created form is
  455.    never destroyed.  All previous instances of the "ModalForm1"
  456.    forms are floating around in Windows.
  457.  
  458.    The Free method of a form can also be used to free its resources.
  459.    This is demonstrated below:
  460.  
  461.    try
  462.      ModalForm1.ShowModal;
  463.      { other stuff here }
  464.    finally
  465.      ModalForm1.Free;
  466.    end;
  467.  
  468. ------------------------------------------------------------------------
  469.  
  470. Q: "What is the best way to create a radio button group and
  471.    place radio buttons on it?  It seems that you can create a
  472.    Radio Group then drop Radio Buttons on it or you can 
  473.    create the group and enter values into the Items properties
  474.    for the titles (captions) of the radio buttons and have
  475.    Delphi place them in the group?"      
  476.  
  477. A: If you're going to use a radio group, you need to create your
  478.    radio buttons using the Items string list.  Radio buttons
  479.    don't have to be in a group, which is why the plain radio 
  480.    button component is available.
  481.  
  482. ------------------------------------------------------------------------
  483.  
  484. Q: "Is there a way to make sure the window that is holding a form 
  485.    or an image component is byte-aligned?" 
  486.  
  487. A: Override the CreateParams method:
  488.  
  489.    procedure TMyForm.CreateParams(var Params:TCreateParams);
  490.    begin
  491.      inherited CreateParams(Params);
  492.      Style := Style or CS_BYTEALIGNWINDOW;
  493.    end; 
  494.  
  495.    Note: Byte alignment is less of a big deal than the Windows docs
  496.    imply.  It is only significant on monochrome, EGA, and 16 color
  497.    VGA video modes. All higher video modes are always byte-aligned.
  498.  
  499. ------------------------------------------------------------------------
  500.  
  501. Q: What is the order of event handlers when a form is created 
  502.    and shown?
  503.  
  504. A: When a form is created the event handlers are executed in the
  505.    following order:  OnCreate, OnShow, OnPaint, OnActivate, OnResize
  506.    and OnPaint again. 
  507.  
  508. ------------------------------------------------------------------------
  509.  
  510. Q: "Why does the error 'Cannot change Visible in OnShow or OnHide'
  511.    occur when the FormStyle property of a form is changed in the
  512.    OnActivate event? 
  513.  
  514. A: The FormStyle property defines how the window gets created and 
  515.    is usually set in the OnCreate event, however, it can changed 
  516.    after the window handle has been created, just not during the
  517.    OnActivate, OnShow or OnHide events.  The issue here is with the
  518.    mode that the system is in during OnShow and OnHide events.
  519.  
  520. ------------------------------------------------------------------------
  521.  
  522. Q: "How can I make components look sunken and raised?
  523.  
  524. A: To make a component look raised or lowered place it on  
  525.    a TBevel or TPanel component which both have properties to
  526.    raise or lower their frames.
  527.  
  528. ------------------------------------------------------------------------
  529.  
  530. Q: Where is the source code for the tabbed controls (i.e.
  531.    TTabbedNotebook)?
  532.  
  533. A: The source code files shipped with Delphi does not contain the
  534.    source for the tabbed controls because of legal reasons. However,
  535.    the interface source for the tabbed controls is provided
  536.    in the DELPHI\DOC directory with an INT extension.
  537.     
  538.    Note: Registered owners of the Delphi RTL source code can request
  539.    the TTabSet and TTabbedNotebook source code from Borland Corporate
  540.    Affairs.  Instructions are in the RTL source readme.
  541.  
  542. ------------------------------------------------------------------------
  543.  
  544. Q: "What is the memo field size in Delphi?"
  545.  
  546. A: Microsoft's edit control that is built-in to Windows and used 
  547.    by Delphi's TEdit and TMemo wrapper classes has a maximum 
  548.    capacity of 32k.  The Delphi wrapper classes do some special
  549.    things  to allow every edit and memo control on a form to
  550.    contain up to 32k each.  Normally all edit controls in an
  551.    application would be limited to 32k collectively.
  552.  
  553. ------------------------------------------------------------------------
  554.  
  555. Q: "How can I make a field in the TGrid component not show up?"
  556.  
  557. A: This can be accomplished by either removing the field entirely 
  558.    from the Fields Editor's field list or by setting the Visible
  559.    property of the field to False. 
  560.  
  561. ------------------------------------------------------------------------
  562.  
  563. Q: "Is there a way to put a wallpaper background on an MDI 
  564.    application?"
  565.  
  566. A: There is a sample application that demostrates this in the VCL
  567.    section (5) of the Delphi forum under the name of MDI_BGRD.ZIP.  
  568.  
  569. ------------------------------------------------------------------------
  570.  
  571. Q: "Does Delphi have a currency/money component?"
  572.  
  573. A: No, bu there is a currency edit component in the VCL section of the
  574.    Delphi forum under the name of CURREDIT.ZIP.  
  575.  
  576. ------------------------------------------------------------------------
  577.  
  578. Q: "Where can I find out about VBX datatypes (i.e. TBasicString) and
  579.    the functions to manipulate these datatypes?"
  580.       
  581. A: First off, all VBX related datatypes and functions are in the 
  582.    VBXCtrls unit which is Borland propriatary unit.  Delphi does,
  583.    however, provide the interface section of this unit is in the
  584.    \DELPHI\DOC directory under the name of VBXCTRLS.INT.  This is the
  585.    only real source of information on the contents of the VBXCtrls unit.
  586.  
  587. ------------------------------------------------------------------------
  588.  
  589. Q: "What issues do I need to be aware of when developing applications
  590.    that will be ran on different screen resolutions (form scaling)?"
  591.  
  592. A: The following are issue to bear in mind when scaling Delphi
  593.    applications (forms) on different screen resolutions?
  594.  
  595.   * Decide early on in the form design stage whether you're going to 
  596.     allow the form to be scaled or not.  The advantage of not scaling is
  597.     that nothing changes at runtime.  The disadvantage of not scaling is
  598.     that nothing changes at runtime (your form may be far too small or
  599.     too large to read on some systems if it is not scaled).
  600.  
  601.   * If you're NOT going to scale the form, set Scaled to False.
  602.  
  603.   * Otherwise, set the Form's Scaled property to True.
  604.  
  605.   * Set AutoScroll to False.  AutoScroll = True means 'don't change the
  606.     form's frame size at runtime' which doesn't look good when the 
  607.     form's contents do change size.
  608.  
  609.   * Set the form's font to a scaleable TrueType font, like Arial.  
  610.     MS San Serif is an ok alternate, but remember that it is still a 
  611.     bitmapped font.  Only Arial will give you a font within a pixel of
  612.     the desired height.  NOTE: If the font used in an application is not
  613.     installed on the target computer, then Windows will select an 
  614.     alternative font within the same font family to use instead. 
  615.     This font may not match the same size of the original font any may
  616.     cause problems.
  617.  
  618.   * Set the form's Position property to something other than poDesigned. 
  619.     poDesigned leaves the form where you left it at design time, which
  620.     for me always winds up way off to the left on my 1280x1024 screen - 
  621.     and completely off the 640x480 screen.
  622.  
  623.   * Don't crowd controls on the form - leave at least 4 pixels between 
  624.     controls, so that a one pixel change in border locations (due to 
  625.     scaling) won't show up as ugly overlapping controls.
  626.  
  627.   * For single line labels that are alLeft or alRight aligned, set
  628.     AutoSize to True.  Otherwise, set AutoSize to False.
  629.  
  630.   * Make sure there is enough blank space in a label component to allow
  631.     for font width changes - a blank space that is 25% of the length of
  632.     the current string display length is a little too much, but safe.
  633.     (You'll need at least 30% expansion space for string labels if you 
  634.     plan to translate your app into other languages) If AutoSize is 
  635.     False, make sure you actually set the label width appropriately. 
  636.     If AutoSize is True, make sure there is enough room for the label 
  637.     to grow on its own.
  638.  
  639.   * In multi-line, word-wrapped labels, leave at least one line of
  640.     blank space at the bottom.  You'll need this to catch the overflow
  641.     when the text wraps differently when the font width changes with
  642.     scaling. Don't assume that because you're using large fonts, you
  643.     don't have to allow for text overflow - somebody else's large 
  644.     fonts may be larger than yours!
  645.  
  646.   * Be careful about opening a project in the IDE at different
  647.     resolutions.  The form's PixelsPerInch property will be modified
  648.     as soon as the form is opened, and will be saved to the DFM if
  649.     you save the project. It's best to test the app by running it
  650.     standalone, and edit the form at only one resolution. Editing
  651.     at varying resolutions and font sizes invites component drift 
  652.     and sizing problems.
  653.  
  654.   * Speaking of component drift, don't rescale a form multiple times,
  655.     at design time or a runtime.  Each rescaling introduces roundoff
  656.     errors which accumulate very quickly since coordinates are 
  657.     strictly integral.  As fractional amounts are truncated off
  658.     control's origins and sizes with each successive rescaling, 
  659.     the controls will appear to creep northwest and get smaller.
  660.     If you want to allow your users to rescale the form any number 
  661.     of times, start with a freshly loaded/created form before each 
  662.     scaling, so that scaling errors do not accumulate.
  663.  
  664.   * Don't change the PixelsPerInch property of the form, period.
  665.  
  666.   * In general, it is not necessary to design forms at any particular
  667.     resolution, but it is crucial that you review their appearance at
  668.     640x480 with small fonts and large, and at a high-resolution with
  669.     small fonts and large before releasing your app.  This should be 
  670.     part of your regular system compatibility testing checklist.
  671.  
  672.   * Pay close attention to any components that are essentially 
  673.     single-line TMemos - things like TDBLookupCombo.  The Windows 
  674.     multi-line edit control always shows only whole lines of text - 
  675.     if the control is too short for its font, a TMemo will show 
  676.     nothing at all (a TEdit will show clipped text). For such 
  677.     components, it's better to make them a few pixels too large than
  678.     to be one pixel too small and show not text at all.
  679.  
  680.   * Keep in mind that all scaling is proportional to the difference 
  681.     in the font height between runtime and design time, NOT the pixel
  682.     resolution or screen size.  Remember also that the origins of your
  683.     controls will be changed when the form is scaled - you can't very 
  684.     well make components bigger without also moving them over a bit.
  685.  
  686. ------------------------------------------------------------------------
  687.  
  688. Q: "How can I get rid of the ReportSmith about box splash screen
  689.    when I run a report."
  690.  
  691. A: Add the following line in [RS_RunTime] section of the 
  692.    RS_RUN.INI file to not have the ReportSmith about box appear
  693.    when a report is ran.
  694.  
  695.    ShowAboutBox=0
  696.  
  697. ------------------------------------------------------------------------
  698.  
  699. Q: "How do you make a moveable multi-split window?"
  700.  
  701. A: The following steps and code demonstrate how to make a
  702.    simple splitter window.
  703.  
  704.    1) Put a memo on a form and set its Align property to alTop. 
  705.    2) Place a panel on the form and set its Align property to alTop.
  706.    3) Set the panel's Height property to 6 or 7. 
  707.    4) Set the panel's DragMode property to dmAutomatic.
  708.    5) Set the panel's DragCursor property to crVSplit.
  709.    6) Set the panel's Cursor property to crVSplit.
  710.    7) Add another memo on the form and set its Align property to
  711.       alClient. 
  712.    8) Now select both memos and the panel, and connect them all
  713.       to this OnDragOver handler:
  714.  
  715.     procedure TForm1.Memo1DragOver(Sender, Source: TObject; X, 
  716.       Y: Integer; State: TDragState; var Accept: Boolean);
  717.     begin
  718.       Accept := False;
  719.       if Source = Panel1 then begin
  720.          Accept := True;
  721.          Memo1.Height := Y + (Sender as TControl).Top;
  722.       end;
  723.     end;
  724.  
  725. ------------------------------------------------------------------------
  726.  
  727. Q: "How can I determine the current row and column position of 
  728.    the caret in a TMemo component?
  729.  
  730. A: You can use the Windows API messages EM_LINEFROMCHAR and
  731.    EM_LINEINDEX to determine the current line and offset within that
  732.    line (starting from SelStart).    
  733.  
  734.    var
  735.      LineNum: longint;
  736.      CharsBeforeLine: longint;
  737.    begin
  738.      LineNum := SendMessage(Memo1.Handle, EM_LINEFROMCHAR, Memo1.SelStart,0);
  739.      CharsBeforeLine := SendMessage(Memo1.Handle, EM_LINEINDEX, LineNum, 0);
  740.      Label1.Caption := 'Line ' + IntToStr(LineNum +1) 
  741.      Lebel2.Caption := 'Position ' + IntToStr((Memo1.SelStart - CharsBeforeLine) + 1);
  742.    end;
  743.  
  744. ------------------------------------------------------------------------
  745.  
  746. Q: How can I get the pixels per inch of the printer? 
  747.  
  748. A: If you want the value in pixels you can use the API function
  749.    GetDeviceCaps().  For example:
  750.  
  751.    VertPixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsX);
  752.    HorzPixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsY);
  753.  
  754. ------------------------------------------------------------------------
  755.  
  756. Q: "Is there a way to store an integer value along with a string
  757.    value in a TString list object or property?"
  758.  
  759. A: Yes, but it requires some type conversions.  The TString 
  760.    component has an Objects array along with the string array 
  761.    that can be utilized for the purpose of storing integer datA:
  762.    The data type that the Objects array holds is TObject.  In 
  763.    essence it holds a 4 byte pointer value.  So to put an integer
  764.    value in it you would need to type cast that value.  For
  765.    example, the following is adding a string and an integer
  766.    value of 100 to an items property (TString object) of a
  767.    Listbox:
  768.  
  769.    Listbox1.Items.AddObject('Text string', TObject(100)); 
  770.  
  771.    To get the value out do the following:
  772.  
  773.    Result := LongInt( Listbox1.Items.Objects[0] ); 
  774.  
  775.    This assumes that Result is of type Longint and that the 
  776.    value that were after is at index position 0.
  777.  
  778.    Note:  Though this works it is never wise to rely on the
  779.    internal workings of an object.  This is trick code and 
  780.    should be well commented.
  781.  
  782.    If you want to keep track of more than one value then a new 
  783.    class can be derived from the TObject base class to hold 
  784.    these values.
  785.   
  786.    type
  787.      ManyValues = class(TObject) 
  788.        Value1 : Integer;
  789.        Value2 : Integer;
  790.      end;
  791.     ...
  792.  
  793. ------------------------------------------------------------------------
  794.  
  795. Q:  Is it possible to access components by their name property (i.e. 
  796.     'SpeedButton' + IntToStr(i) )
  797.  
  798. A: Yes it's possible.  The following example uses the FindComponent
  799.    method of Form1 to disable the first 10 SpeedButtons by name. 
  800.  
  801.    for I := 1 to 10 do
  802.      with Form1.FindComponent('SpeedButton' + IntToStr(i)) as TSpeedButton do
  803.         Enabled := False;
  804.  
  805.  
  806. ------------------------------------------------------------------------
  807.  
  808. Q: How do you create a 'modal' form in an MDI application?  When my 
  809.    application calls the ShowModal method I get an error "Can't Show Modal
  810.    when Visible is set true".  When I try to set Visible to False, I get 
  811.    the error, can't set Visible to False on an MDI Child.
  812.  
  813. A: Normally, the first form of a project (the main form) is created with
  814.    its Visible property set to True, and all of the other forms are created
  815.    with their Visible properties set to False. An MDI child form, on the 
  816.    other hand, can't be invisible, so its Visible property is set to True.
  817.    When you change its form style back to fsNormal, the Visible property 
  818.    stays True, so you need to set it to False manually.
  819.  
  820. ------------------------------------------------------------------------
  821.  
  822. Q: Is there a way to change the default font size for components when
  823.    they are placed on a form?
  824.  
  825. A: Just add a form with it's Font property set to your desired font to the
  826.    gallery. Since, by default, components reflect the parent's font any
  827.    components you add to your form will take on that font. In addition,
  828.    you can set your new form as the Default Main Form and Default New
  829.    Form from the gallery (Options | Gallery...).
  830.  
  831. ------------------------------------------------------------------------
  832.  
  833. Q: How can I determine the directory that my program was executed
  834.    from?
  835.  
  836. A: The following function extracts the path from the ExeName
  837.    property of the global Application object.
  838.  
  839.    function GetExePath : String;
  840.    var
  841.      LastBackSlashPos, Index : Integer;
  842.    begin
  843.      Result := Application.ExeName; 
  844.      for Index := 1 to length(Result) do
  845.        if Result[Index] = '\' then
  846.           LastBackSlashPos := Index;
  847.      { subtract 1 so that the last backslash is not included }
  848.      Result[0] := chr(LastBackSlashPos - 1);
  849.    end;
  850.  
  851. ------------------------------------------------------------------------
  852.  
  853. Q: How can I change Font.Style back to normal after calling 
  854.    Canvas.Font.Style := [fsBold]?  The online help shows 
  855.    ([fsBold],[fsItalic] etc] but does not mention normal style.
  856.  
  857. A:  You simply specify an empty set for no style at all:
  858.  
  859.     Canvas.Font.Style := []; 
  860.  
  861.     or, you might just want to exclude the fsBold style like this:
  862.  
  863.     Canvas.Font.Style := Canvas.Font.Style - [fsBold];
  864.  
  865. ------------------------------------------------------------------------
  866.  
  867. Q: How can I get some actions to happen after a form is showing 
  868.    normally?  It seems that all the form events (OnCreate, OnPaint,
  869.    etc.) happen before the form is show.
  870.  
  871. A: You can add "Visible := True" inside OnCreate event, and then
  872.    do whatever you wish.
  873.  
  874. ------------------------------------------------------------------------
  875.  
  876. Q:  How much GDI resource does each built-in components use?
  877.  
  878. A: The TGraphicControl descendants like TLabel and TBevel don't use
  879.    free system resources at all. On the other hand, TWinControl descendants 
  880.    like TEdit and TPanel do.  Also each radio button in a TRadioGroup is a
  881.    window, i.e. has a window handle.
  882.  
  883. ------------------------------------------------------------------------
  884.  
  885. Q: Why does a TTabbedNotebook use so much of the system resources
  886.    when only one page is showing at a time?
  887.  
  888. A: Even though only one page is showing at a time each pages'
  889.    components have already been created thus taking resources.
  890.    One solution to this is instead of using a notebook you use 
  891.    a separate form for each page and when the user clicks on a
  892.    tab, the existing page is destroyed and the new one created.
  893.    The basic steps to set this is is as follows:
  894.  
  895.    First, each child form needs its creation parameters setup 
  896.    in a certain way:
  897.  
  898.    ...
  899.    private
  900.      { Private declarations }
  901.      PROCEDURE CreateParams(VAR Params: TCreateParams); override;
  902.    ...
  903.    procedure TForm2.CreateParams(VAR Params: TCreateParams);
  904.    begin
  905.      Inherited  CreateParams(Params);
  906.      with Params do begin
  907.        WndParent := Application.MainForm.Handle;
  908.        Style := (Style OR WS_CHILD) AND NOT (WS_POPUP);
  909.      end;
  910.    end;
  911.  
  912.     The child form's BorderStyle must be set to bsNone. In the
  913.     main form, create a private data field Child of type TForm. 
  914.     Initialize it in the OnActivate event, NOT OnCreate. And each
  915.     time the tab is clicked to change "pages", free the existing 
  916.     Child and initialize a new one of the desired type. E.g. in 
  917.     OnActivate do:
  918.  
  919.      Child := TForm2.Create(Self);
  920.      with Child do begin
  921.        Parent := Self;
  922.        Align := alClient;
  923.        Visible := True;
  924.      end;
  925.  
  926.     When you create a child page due to a tab change, do it in the
  927.     same way just shown. Of course you'll need to use the main form
  928.     to store any data about the state of the controls in a given
  929.     child window, because the data will go bye-bye when the child
  930.     is freed.
  931.  
  932. ------------------------------------------------------------------------
  933.  
  934. Q. How do you deselect one or more items in a listbox or combobox?
  935.  
  936. A. Listbox1.ItemIndex := -1;
  937.  
  938. ------------------------------------------------------------------------
  939.  
  940. Q. Why is it that when I call a dialog window such as MessageBox()
  941.    from within an event handler such as OnExit that the blinking 
  942.    cursor (the caret) disappears upon closing the dialog?
  943.  
  944. A. This is a Windows behavior.  Forcing an additional focus change
  945.    (e.g., with ShowMessage) during an event associated with a focus 
  946.    change (e.g., OnExit) will cause Windows to become confused.  It is
  947.    Windows that is controlling the focus change, and it is Windows that
  948.    becomes confused when you force a focus change in the middle of that
  949.    process.
  950.  
  951. ------------------------------------------------------------------------
  952.  
  953. Q.  Why do I get the exception 'EInvalidOperation: Cannot make a visalbe 
  954.     window modal' when I try to open a form with Showmodal?  The form is
  955.     not open yet.
  956.  
  957. A.  Make sure the form's Visible property is not being set to Ture at 
  958.     design-time or run-time.
  959.  
  960. ------------------------------------------------------------------------
  961.  
  962. Q. Why do I get the message 'Unable to load RPTSMITH.EXE' when I
  963.    double click on the TReport componet on the form?  It should
  964.    bring up ReportSmith.
  965.  
  966. A. Either the [ReportSmith] section is missing or incorrect in
  967.    the DELPHI.INI file.  Make sure that it specifies the correct
  968.    path.  e.g.
  969.  
  970.    [ReportSmith]
  971.    ExePath=C:\RPTSMITH
  972.