home *** CD-ROM | disk | FTP | other *** search
- SECTION 5 - Delphi VCL
-
- This document contains information that is most often provided
- to users of this section. There is a listing of common
- Technical Information Documents that can be downloaded from
- the libraries, and a listing of the most frequently asked
- questions and their answers.
-
- Technical Information Documents related to VCL components:
-
- None
-
- Zip files related to VCL components:
-
- MDI_BGRD.ZIP Sample MDI application with a wallpaper background.
- CURREDIT.ZIP Currency edit component.
-
- Questions and answers:
-
- Q. "How can VCL components be created on the fly at run-time?"
-
- A. * The following code will create a modal password form at runtime.
- The TPasswordForm type is a TForm descendent class defined either
- in the current unit or in a separate unit referenced by the current
- unit's uses clause.
-
- with TPasswordForm.Create(Application) do
- begin ( i.e TForm1, TPasswordForm etc. }
- ShowModal; { Display form as a modal window }
- Free; { Free the form when it is closed }
- end;
-
- * The following are the general steps to add a component to a form at
- run-time:
-
- 1. Declare an instance variable of the component type that you wish to
- create {i.e. TButton }. Note: instance variables are used to point
- to an actual instance of an object. They are not objects themselves.
- 2. Use the component's Create constructor to create an instance
- of the component and assign the instance to the instance
- variable declared in step 1. All components' Create constructors
- take a parameter - the component's owner. Except in special
- circumstances, you should always pass the form as the owner
- parameter of the component's Create constructor.
- 3. Assign a parent to the component's Parent property (i.e. Form1,
- Panel1, etc). The Parent determines where the component will be
- displayed, and how the component's Top and Left coordinates are
- interpreted. To place a component in a groupbox, set the
- component's Parent property to the groupbox. For a component
- to be visible, it must have a parent to display itself within.
- 4. Set any other properties that are necessary (i.e. Width, Height).
- 5. Finally, make the component appear on the form by setting the
- component's Visible property to True.
- 6. If you created the component with an owner, you
- don't need to do anything to free the component - it will be freed
- when the owner is destroyed. If you did not give the component an
- owner when you created it, you are responsible for making sure
- the component is freed when it is no longer needed.
-
- The following demonstrates how to add a TButton component to the
- current form at run-time:
-
- var
- TempButton : TButton; { This is only a pointer to a TButton }
- begin
- TempButton := TButton.Create(Self); { Self refers to the form }
- TempButton.Parent := Self; { Must assign the Parent }
- TempButton.Caption := 'Run-time'; { Assign properties now }
- TempButton.Visible := True; { Show to button }
- end;
-
- Since the button was created with an owner, it will be freed
- automatically when its owner, the form, is freed.
-
-
- Q. "How can the event handler of a popup menu item determine which
- component was right-clicked upon to activate that menu?
-
- A. Use the PopupMenu.PopupComponent property
- to determine what control the menu was activated for.
-
- procedure TForm1.PopupItem1Click(Sender: TObject);
- begin
- Label1.Caption := PopupMenu1.PopupComponent.ClassName;
- end;
-
- The form's ActiveControl property can also be used, however,
- the active control may not necessarily be the control that
- caused the popup menu to appear.
-
-
- Q. "What are the capacity limits of the standard Delphi controls?"
-
- A. Any component that uses a TList to store information has an upper
- bound of 16368 items. For example, a TTabControl can contain up to
- 16368 tabs and the Delphi Component Palette can contain up to
- 16368 palette pages.
-
- Many of the Delphi standard components are wrappers around standard
- Windows controls. Windows 3.1 imposes its own limits on these
- components. For example: a TComboBox or TListbox can hold up to
- 5440 items and TMemo or TEdit (and related components) can hold up
- to 32k of text.
-
- Windows 3.1 resource space imposes a limit of 570 pages in a
- TNoteBook component. (It's difficult to get more than 500 window
- handles in any Windows application.)
-
- Note 1: Exceeding these limits will raise exceptions or cause Windows
- to behave strangely.
-
- Note 2: Many of the Windows-based capacity limits are much higher
- in the 16-bit WOW box of Windows NT and in Windows 95. In future
- 32 bit releases of Delphi, virtually all of these limits will
- disappear.
-
-
- Q. How can I determine the Length in pixels of a string after a
- specific font has been aplied to it.
-
- A. Use the Canvas methods TextHeight and TextWidth to
- determine the text height and width of a string in
- pixels. Be sure to assign the font into the Canvas before
- drawing or taking measurements.
-
- All visual components have a Canvas property, but
- usually this property is protected so that only direct descendents
- can draw on the Canvas. Since you write much of your code
- inside methods of a TForm descendent, you always have access to
- your form's inherited Canvas property. The TPaintBox component
- makes its Canvas property public so that you can draw on the
- component from OnPaint event methods in the form.
-
- If a component doesn't have a Canvas property you can use the
- following function to get the text width based on the font passed.
-
- function GetTextWidth(CanvasOwner: TForm; Text : String;
- TextFont : TFont): Integer;
- var
- OldFont : TFont;
- begin
- OldFont := TFont.Create;
- try
- OldFont.Assign( CanvasOWner.Font );
- CanvasOWner.Font.Assign( TextFont );
- Result := CanvasOwner.Canvas.TextWidth(Text);
- CanvasOWner.Font.Assign( OldFont );
- finally
- OldFont.Free;
- end;
- end;
-
-
- Q. Why do some visual components like TPanel and TEdit not have a
- Canvas property?
-
- A. All descendents of TCustomControl have a Canvas property, however,
- most are protected to prevent 'outsiders' from drawing on the
- component. Descendents of a component can always access the
- protected properties they inherit from the component
- (such as Canvas), but users of the component cannot.
-
- type
- TCanvasPanel = class(TPanel)
- public
- property Canvas;
- end;
-
- If you want to draw on a component that doesn't have a public
- canvas property, consider using a different component that was
- intended for arbitrary drawing (TPaintBox), or layer components to
- achieve the desired result (client-align a TPaintBox inside a TPanel
- to get a bevelled, drawable area).
-
-
- Q. "How can I get a horizontal scrollbar on a list box?"
-
- A. Send a LB_SetHorizontalExtent message to the listbox's window handle.
- For example, the message could be sent in the form's OnCreate:
-
- procedure TForm1.FormCreate(Sender: TObject);
- begin
- SendMessage(Listbox1.Handle, LB_SetHorizontalExtent,
- 1000, Longint(0));
- end;
-
- Q. "Does Delphi have a component that supports serial communications?"
-
- A. No. However, there are serial communications libraries (and soon
- Delphi components) for Delphi available from third party vendors
- such as TurboPower, SaxComm, and and others.
-
-
- Q. "How can the tab stops be set in a TMemo control?"
-
- A. To change the tab stops for a multiline edit control
- (i.e. a TMemo) send the EM_SetTabStops message to the
- component. The Tabs array indicates where the tab stops
- will be located. Since the WParam parameter to
- SendMessage is 1, then all tab stops will be set to the
- value passed in the Tabs array. Remember to set the
- WantTabs property of TMemo to True to enable the tabs.
-
- procedure TForm1.FormCreate( Sender : TObject );
- const
- TabInc : LongInt = 10;
- begin
- SendMessage( Memo1.Handle, EM_SetTabStops, 1,
- Longint( @TabInc ) );
- end;
-
-
- Q. "Where is the best place to open a splash screen on program
- start up?"
-
- A. The best place to open a splash screen is in the project source
- file after the first Application.FormCreate and before the
- Application.Run. This is accomplished by creating a form on
- the fly and then displaying it before the application is actual
- opened.
-
- program Project1;
-
- uses Forms,
- Unit1 in 'UNIT1.PAS' {Form1},
- Splash;
-
- {$R *.RES}
- var
- SplashScreen : TSplashScreen; {in the Splash unit}
- begin
- Application.CreateForm(TForm1, Form1);
- SplashScreen := TSplashScreen.Create(Application);
- try
- SplashScreen.Show;
- SplashScreen.Update;
- {
- do other CreatForms or anyother processing
- before the app is to be opened
- }
- finally {Make sure the splash screen gets released}
- SplashScreen.Free;
- end;
- Application.Run;
- end.
-
-
- Q. "Why does the OnExit event of a TEdit component not execute when
- the user clicks on a speed button? Is there a way to make a
- an OnExit event execute when a speed button is pressed?"
-
- A. A speed button never actually gets focus, so the active
- control never loses its focus, consequently the active
- control's OnExit event never occurs.
-
- One way to execute the active control's OnExit event is to
- explicitly call it in the OnClick event of the speedbutton.
- For example:
-
- procedure TForm1.SpeedButton1Click(Sender: TObject);
- begin
- If ActiveControl is TEdit then
- (ActiveControl as TEdit).OnExit(ActiveControl);
- end;
-
-
- Q. "When I open the child windows at run-time each one is
- positioned slightly down and to the right of the previous
- window. My problem is that if I then close some of the child
- windows and then open a new one, the new one is placed
- down and to the right of where the last child window was
- before I closed it, even though it is no longer there!
- Is this as designed?"
-
- A. That's how MDI windows works. VCL doesn't override Windows
- default behavior in this situation.
-
- Untested suggestion: In the FormCreate procedure try
- setting the Top, Left, Width & Height properties to the values
- that you require. The MDI child form's FormCreate is called
- before the window is displayed.
-
-
- Q. "Why can't my program find any of the resources that I put in a .RES
- file if that .RES file is the same name as my form's unit name?"
-
- A. If the name of an included .RES file is the same as the name
- of a .DPR file Delphi wll overwrite it with it's own .RES file.
- In addition, the project RES file is for the Delphi project
- manager only; don't edit or add resources to this RES file.
-
-
- Q. "How can you do scrolling functions in a TForm component using
- keyboard commands? For example, scrolling the form up and down
- with the PgUp and PgDn keys.
-
- A. Form scrolling is accomplished by modifying the VertScrollbar
- or HorzScrollbar Postion properties of the form. The following
- code demonstrates how to do this:
-
- procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- const
- PageDelta = 10;
- begin
- With VertScrollbar do
- if Key = VK_NEXT then Position := Position+PageDelta
- else if Key = VK_PRIOR then Position := Position-PageDelta;
- end;
-
- Note: This may not work well if the active control uses PgUp & PgDn,
- too, like a TMemo.
-
-
- Q. "Is there a way to fill a TListbox or TMemo in one shot?"
-
- A. To fill multiple lines of a TListbox or TMemo component the SetText
- method can be used. The null terminated string passed to the
- SetText method is a concatination of each line of text delimeted
- by a carriage return character #13 in between. For example,
- the follow statement:
-
- Listbox1.Items.SetText('aaaaa'#13'bbbbb'#13'ccccc')
-
- will display the following in a listbox window:
-
- aaaaa
- bbbbb
- ccccc
-
- Note: The preferred method of filling a listbox or memo is with the
- Add method of their Items and Lines properties, respectfully.
-
-
- Q. "Is it possible to create something like the Control Array in Visual
- Basic? For example, I want a group of buttons with a common event
- handler whereby the event handler picks up an integer value for the
- particular button. In Visual Basic this would be done via the
- Control Array index."
-
- A. One way do to this is to set the Tag field for each button to a
- different number and then create a common OnClick event handler
- that looks at the Sender's Tag field. Assign the same OnClick
- event handler to all the buttons in the group. And then the
- OnClick event handler would look something like this:
-
- procedure TForm1.Button1Click(Sender: TObject); var cap: string;
- begin
- case TButton(sender).Tag of
- 1: ShowMessage('1st Button Pressed');
- 2: ShowMessage('2nd Button Pressed');
- 3: ShowMessage('3rd Button Pressed');
- end;
- end;
-
-
- Q. "How can a new component be added to a page of a
- TTabbedNoteBook at run time? How do I determine
- what the parent will be for the new component?"
-
-
- A. To add a component to a TabbedNotebook page at run-time a
- pointer to the desired page must be assigned to the new
- component's Parent property before it can be shown. The way to
- access all the pages of a TTabbedNotebook at run-time is with
- the Objects array property of the TabbedNotebook's Pages property.
- In other words, the page components are stored as objects attached
- to the page names in the Pages string list property. The follow
- demonstrates the creation of a button on the second page of
- TabbedNotebook1:
-
- var
- NewButton : TButton;
- begin
- NewButton := TButton.Create(Self);
- NewButton.Parent := TWinControl(TabbedNotebook1.Pages.Objects[1])
- ...
-
- This is how a TNotebook page would be used as a parent to a newly
- created component on that page:
-
- NewButton.Parent := TWinControl(Notebook1.Pages.Objects[1])
-
- This is how a TTabSet tab page would be used as a parent to a
- newly created component on that tab page:
-
- NewButton.Parent := TWinControl(TabSet1.Tabs.Objects[1])
-
-
- Q. "Are there any vertical ( side of the page ) tab components
- available, commercial, shareware or freeware."
-
- A. TurboPower's Orpheus product will support this. GO TURBOPOWER
- for more information.
-
-
- Q. "Is there an easy way to get CopyToClipboard, CutToClipboard etc.
- to know to use the TEdit that has focus?
-
- A. Simply check to see if the ActiveControl is of type TEdit and then
- do the desired cut, copy or paste operation. For example:
-
- if (ActiveControl is TEdit) then
- TEdit(ActiveControl).CopyToClipboard;
-
-
- Q. "Does a TDBGrid component have an OnMouseDown, OnMouseUp and
- OnMouseMove events?"
-
- A. The events are there, but they aren't published. You could
- create a simple decendant of TDBGrid and publish them.
-
-
- Q. "Does Delphi grab system resources when displaying and closing
- modal dialogs? For example, the following code decreases the
- system resources every time it is used to show a modal dialog."
-
- ModalForm1 := TModalForm1.Create(Self);
- ModalForm1.ShowModal;
-
- A. Without an OnClose event handler that sets Action parameter to
- caFree, your code is creating a new form with each call to
- TModalForm1.Create(Self), but the previously created form is
- never destroyed. All previous instances of the "ModalForm1"
- forms are floating around in Windows.
-
- The Free method of a form can also be used to free its resources.
- This is demonstrated below:
-
- try
- ModalForm1.ShowModal;
- { other stuff here }
- finally
- ModalForm1.Free;
- end;
-
-
- Q. What is the best way to create a radio button group and
- place radio buttons on it? It seems that you can create a
- Radio Group then drop Radio Buttons on it or you can
- create the group and enter values into the Items properties
- for the titles (captions) of the radio buttons and have
- Delphi place them in the group.
-
- A. If you're going to use a radio group, you need to create your
- radio buttons using the Items string list. Radio buttons
- don't have to be in a group, which is why the plain radio
- button component is available.
-
-
- Q. "Is there a way to make sure the window that is holding a form
- or an image component is byte-aligned?"
-
- A. Override the CreateParams method:
-
- procedure TMyForm.CreateParams(var Params:TCreateParams);
- begin
- inherited CreateParams(Params);
- Style := Style or CS_BYTEALIGNWINDOW;
- end;
-
- Note: Byte alignment is less of a big deal than the Windows docs
- imply. It is only significant on monochrome, EGA, and 16 color
- VGA video modes. All higher video modes are always byte-aligned.
-
-
- Q. What is the order of event handlers when a form is created
- and shown?
-
- A. When a form is created the event handlers are executed in the
- following order: OnCreate, OnShow, OnPaint, OnActivate, OnResize
- and OnPaint again.
-
-
- Q. "Why does the error 'Cannot change Visible in OnShow or OnHide'
- occur when the FormStyle property of a form is changed in the
- OnActivate event?
-
- A. The FormStyle property defines how the window gets created and
- is usually set in the OnCreate event, however, it can changed
- after the window handle has been created, just not during the
- OnActivate, OnShow or OnHide events. The issue here is with the
- mode that the system is in during OnShow and OnHide events.
-
-
- Q. "How can I make components look sunken and raised?
-
- A. To make a component look raised or lowered place it on
- a TBevel or TPanel component which both have properties to
- raise or lower their frames.
-
-
- Q. Where is the source code for the tabbed controls (i.e.
- TTabbedNotebook)?
-
- A. The source code files shipped with Delphi does not contain the
- source for the tabbed controls because of legal reasons. However,
- the interface source for the tabbed controls is provided
- in the DELPHI\DOC directory with an INT extension.
-
- Note: Registered owners of the Delphi RTL source code can request
- the TTabSet and TTabbedNotebook source code from Borland Corporate
- Affairs. Instructions are in the RTL source readme.
-
-
- Q. "What is the memo field size in Delphi?"
-
- A. Microsoft's edit control that is built-in to Windows and used
- by Delphi's TEdit and TMemo wrapper classes has a maximum
- capacity of 32k. The Delphi wrapper classes do some special
- things to allow every edit and memo control on a form to
- contain up to 32k each. Normally all edit controls in an
- application would be limited to 32k collectively.
-
-
- Q. "How can I make a field in the TGrid component not show up?"
-
- A. This can be accomplished by either removing the field entirely
- from the Fields Editor's field list or by setting the Visible
- property of the field to False.
-
-
- Q. "Is there a way to put a wallpaper background on an MDI
- application?"
-
- A. There is a sample application that demostrates this in the VCL
- section (5) of the Delphi forum under the name of MDI_BGRD.ZIP.
-
-
- Q. "Does Delphi have a currency/money component?"
-
- A. No, bu there is a currency edit component in the VCL section of the
- Delphi forum under the name of CURREDIT.ZIP.
-
-
- Q. "Where can I find out about VBX datatypes (i.e. TBasicString) and
- the functions to manipulate these datatypes?"
-
- A. First off, all VBX related datatypes and functions are in the
- VBXCtrls unit which is Borland propriatary unit. Delphi does,
- however, provide the interface section of this unit is in the
- \DELPHI\DOC directory under the name of VBXCTRLS.INT. This is the
- only real source of information on the contents of the VBXCtrls unit.
-
-
- Q. "What issues do I need to be aware of when developing applications
- that will be ran on different screen resolutions (form scaling)?"
-
- A. The following are issue to bear in mind when scaling Delphi
- applications (forms) on different screen resolutions?
-
- * Decide early on in the form design stage whether you're going to
- allow the form to be scaled or not. The advantage of not scaling is
- that nothing changes at runtime. The disadvantage of not scaling is
- that nothing changes at runtime (your form may be far too small or
- too large to read on some systems if it is not scaled).
-
- * If you're NOT going to scale the form, set Scaled to False.
-
- * Otherwise, set the Form's Scaled property to True.
-
- * Set AutoScroll to False. AutoScroll = True means 'don't change the
- form's frame size at runtime' which doesn't look good when the
- form's contents do change size.
-
- * Set the form's font to a scaleable TrueType font, like Arial.
- MS San Serif is an ok alternate, but remember that it is still a
- bitmapped font. Only Arial will give you a font within a pixel of
- the desired height. NOTE: If the font used in an application is not
- installed on the target computer, then Windows will select an
- alternative font within the same font family to use instead.
- This font may not match the same size of the original font any may
- cause problems.
-
- * Set the form's Position property to something other than poDesigned.
- poDesigned leaves the form where you left it at design time, which
- for me always winds up way off to the left on my 1280x1024 screen -
- and completely off the 640x480 screen.
-
- * Don't crowd controls on the form - leave at least 4 pixels between
- controls, so that a one pixel change in border locations (due to
- scaling) won't show up as ugly overlapping controls.
-
- * For single line labels that are alLeft or alRight aligned, set
- AutoSize to True. Otherwise, set AutoSize to False.
-
- * Make sure there is enough blank space in a label component to allow
- for font width changes - a blank space that is 25% of the length of
- the current string display length is a little too much, but safe.
- (You'll need at least 30% expansion space for string labels if you
- plan to translate your app into other languages) If AutoSize is
- False, make sure you actually set the label width appropriately.
- If AutoSize is True, make sure there is enough room for the label
- to grow on its own.
-
- * In multi-line, word-wrapped labels, leave at least one line of
- blank space at the bottom. You'll need this to catch the overflow
- when the text wraps differently when the font width changes with
- scaling. Don't assume that because you're using large fonts, you
- don't have to allow for text overflow - somebody else's large
- fonts may be larger than yours!
-
- * Be careful about opening a project in the IDE at different
- resolutions. The form's PixelsPerInch property will be modified
- as soon as the form is opened, and will be saved to the DFM if
- you save the project. It's best to test the app by running it
- standalone, and edit the form at only one resolution. Editing
- at varying resolutions and font sizes invites component drift
- and sizing problems.
-
- * Speaking of component drift, don't rescale a form multiple times,
- at design time or a runtime. Each rescaling introduces roundoff
- errors which accumulate very quickly since coordinates are
- strictly integral. As fractional amounts are truncated off
- control's origins and sizes with each successive rescaling,
- the controls will appear to creep northwest and get smaller.
- If you want to allow your users to rescale the form any number
- of times, start with a freshly loaded/created form before each
- scaling, so that scaling errors do not accumulate.
-
- * Don't change the PixelsPerInch property of the form, period.
-
- * In general, it is not necessary to design forms at any particular
- resolution, but it is crucial that you review their appearance at
- 640x480 with small fonts and large, and at a high-resolution with
- small fonts and large before releasing your app. This should be
- part of your regular system compatibility testing checklist.
-
- * Pay close attention to any components that are essentially
- single-line TMemos - things like TDBLookupCombo. The Windows
- multi-line edit control always shows only whole lines of text -
- if the control is too short for its font, a TMemo will show
- nothing at all (a TEdit will show clipped text). For such
- components, it's better to make them a few pixels too large than
- to be one pixel too small and show not text at all.
-
- * Keep in mind that all scaling is proportional to the difference
- in the font height between runtime and design time, NOT the pixel
- resolution or screen size. Remember also that the origins of your
- controls will be changed when the form is scaled - you can't very
- well make components bigger without also moving them over a bit.
-
-