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.
-
- TI1171 Bug Report Form
- TI2711 How to Circumvent the "Index not found" Exception
- TI2776 List of Delphi books from Third-Party Publishers
- TI2779 Delphi Client/Server and PowerBuilder Compared
- TI2781 Step by Step Configuration of an ODBC Driver
- TI2841 Delphi Consultants and Training Centers
-
- Delphi FTP and WWW sites on Internet:
-
- ftp.borland.com
- ftp.netcom.com /pub/ic/ice-floe.
-
- http://www.Borland.com
- http://www.cybernetics.net/users/bstowers/delphi-bugs.html
- http://www.coriolis.com/coriolis/whatsnew/delphi.htm
-
- Zip files related to VCL components:
-
- VCLPATCH.ZIP Patch for the Visual Component Library source.
- DELCSPAT.ZIP Patch for Delphi Client Server.
- DELPATCH.ZIP Patch for Delphi
-
- 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; {Process any pending Windows paint messages}
- {
- do other CreatForms or any other processing before the
- application is to be opened. If the start up processing is
- going to take a long time you may want to run
- Application.ProcessMessages periodically to allow Windows
- to respond to Windows messages.
- }
- 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.
-
- ------------------------------------------------------------------------
-
- Q: "How can I get rid of the ReportSmith about box splash screen
- when I run a report."
-
- A: Add the following line in [RS_RunTime] section of the
- RS_RUN.INI file to not have the ReportSmith about box appear
- when a report is ran.
-
- ShowAboutBox=0
-
- ------------------------------------------------------------------------
-
- Q: "How do you make a moveable multi-split window?"
-
- A: The following steps and code demonstrate how to make a
- simple splitter window.
-
- 1) Put a memo on a form and set its Align property to alTop.
- 2) Place a panel on the form and set its Align property to alTop.
- 3) Set the panel's Height property to 6 or 7.
- 4) Set the panel's DragMode property to dmAutomatic.
- 5) Set the panel's DragCursor property to crVSplit.
- 6) Set the panel's Cursor property to crVSplit.
- 7) Add another memo on the form and set its Align property to
- alClient.
- 8) Now select both memos and the panel, and connect them all
- to this OnDragOver handler:
-
- procedure TForm1.Memo1DragOver(Sender, Source: TObject; X,
- Y: Integer; State: TDragState; var Accept: Boolean);
- begin
- Accept := False;
- if Source = Panel1 then begin
- Accept := True;
- Memo1.Height := Y + (Sender as TControl).Top;
- end;
- end;
-
- ------------------------------------------------------------------------
-
- Q: "How can I determine the current row and column position of
- the caret in a TMemo component?
-
- A: You can use the Windows API messages EM_LINEFROMCHAR and
- EM_LINEINDEX to determine the current line and offset within that
- line (starting from SelStart).
-
- var
- LineNum: longint;
- CharsBeforeLine: longint;
- begin
- LineNum := SendMessage(Memo1.Handle, EM_LINEFROMCHAR, Memo1.SelStart,0);
- CharsBeforeLine := SendMessage(Memo1.Handle, EM_LINEINDEX, LineNum, 0);
- Label1.Caption := 'Line ' + IntToStr(LineNum +1)
- Lebel2.Caption := 'Position ' + IntToStr((Memo1.SelStart - CharsBeforeLine) + 1);
- end;
-
- ------------------------------------------------------------------------
-
- Q: How can I get the pixels per inch of the printer?
-
- A: If you want the value in pixels you can use the API function
- GetDeviceCaps(). For example:
-
- VertPixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsX);
- HorzPixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsY);
-
- ------------------------------------------------------------------------
-
- Q: "Is there a way to store an integer value along with a string
- value in a TString list object or property?"
-
- A: Yes, but it requires some type conversions. The TString
- component has an Objects array along with the string array
- that can be utilized for the purpose of storing integer datA:
- The data type that the Objects array holds is TObject. In
- essence it holds a 4 byte pointer value. So to put an integer
- value in it you would need to type cast that value. For
- example, the following is adding a string and an integer
- value of 100 to an items property (TString object) of a
- Listbox:
-
- Listbox1.Items.AddObject('Text string', TObject(100));
-
- To get the value out do the following:
-
- Result := LongInt( Listbox1.Items.Objects[0] );
-
- This assumes that Result is of type Longint and that the
- value that were after is at index position 0.
-
- Note: Though this works it is never wise to rely on the
- internal workings of an object. This is trick code and
- should be well commented.
-
- If you want to keep track of more than one value then a new
- class can be derived from the TObject base class to hold
- these values.
-
- type
- ManyValues = class(TObject)
- Value1 : Integer;
- Value2 : Integer;
- end;
- ...
-
- ------------------------------------------------------------------------
-
- Q: Is it possible to access components by their name property (i.e.
- 'SpeedButton' + IntToStr(i) )
-
- A: Yes it's possible. The following example uses the FindComponent
- method of Form1 to disable the first 10 SpeedButtons by name.
-
- for I := 1 to 10 do
- with Form1.FindComponent('SpeedButton' + IntToStr(i)) as TSpeedButton do
- Enabled := False;
-
-
- ------------------------------------------------------------------------
-
- Q: How do you create a 'modal' form in an MDI application? When my
- application calls the ShowModal method I get an error "Can't Show Modal
- when Visible is set true". When I try to set Visible to False, I get
- the error, can't set Visible to False on an MDI Child.
-
- A: Normally, the first form of a project (the main form) is created with
- its Visible property set to True, and all of the other forms are created
- with their Visible properties set to False. An MDI child form, on the
- other hand, can't be invisible, so its Visible property is set to True.
- When you change its form style back to fsNormal, the Visible property
- stays True, so you need to set it to False manually.
-
- ------------------------------------------------------------------------
-
- Q: Is there a way to change the default font size for components when
- they are placed on a form?
-
- A: Just add a form with it's Font property set to your desired font to the
- gallery. Since, by default, components reflect the parent's font any
- components you add to your form will take on that font. In addition,
- you can set your new form as the Default Main Form and Default New
- Form from the gallery (Options | Gallery...).
-
- ------------------------------------------------------------------------
-
- Q: How can I determine the directory that my program was executed
- from?
-
- A: The following function extracts the path from the ExeName
- property of the global Application object.
-
- function GetExePath : String;
- var
- LastBackSlashPos, Index : Integer;
- begin
- Result := Application.ExeName;
- for Index := 1 to length(Result) do
- if Result[Index] = '\' then
- LastBackSlashPos := Index;
- { subtract 1 so that the last backslash is not included }
- Result[0] := chr(LastBackSlashPos - 1);
- end;
-
- ------------------------------------------------------------------------
-
- Q: How can I change Font.Style back to normal after calling
- Canvas.Font.Style := [fsBold]? The online help shows
- ([fsBold],[fsItalic] etc] but does not mention normal style.
-
- A: You simply specify an empty set for no style at all:
-
- Canvas.Font.Style := [];
-
- or, you might just want to exclude the fsBold style like this:
-
- Canvas.Font.Style := Canvas.Font.Style - [fsBold];
-
- ------------------------------------------------------------------------
-
- Q: How can I get some actions to happen after a form is showing
- normally? It seems that all the form events (OnCreate, OnPaint,
- etc.) happen before the form is show.
-
- A: You can add "Visible := True" inside OnCreate event, and then
- do whatever you wish.
-
- ------------------------------------------------------------------------
-
- Q: How much GDI resource does each built-in components use?
-
- A: The TGraphicControl descendants like TLabel and TBevel don't use
- free system resources at all. On the other hand, TWinControl descendants
- like TEdit and TPanel do. Also each radio button in a TRadioGroup is a
- window, i.e. has a window handle.
-
- ------------------------------------------------------------------------
-
- Q: Why does a TTabbedNotebook use so much of the system resources
- when only one page is showing at a time?
-
- A: Even though only one page is showing at a time each pages'
- components have already been created thus taking resources.
- One solution to this is instead of using a notebook you use
- a separate form for each page and when the user clicks on a
- tab, the existing page is destroyed and the new one created.
- The basic steps to set this is is as follows:
-
- First, each child form needs its creation parameters setup
- in a certain way:
-
- ...
- private
- { Private declarations }
- PROCEDURE CreateParams(VAR Params: TCreateParams); override;
- ...
- procedure TForm2.CreateParams(VAR Params: TCreateParams);
- begin
- Inherited CreateParams(Params);
- with Params do begin
- WndParent := Application.MainForm.Handle;
- Style := (Style OR WS_CHILD) AND NOT (WS_POPUP);
- end;
- end;
-
- The child form's BorderStyle must be set to bsNone. In the
- main form, create a private data field Child of type TForm.
- Initialize it in the OnActivate event, NOT OnCreate. And each
- time the tab is clicked to change "pages", free the existing
- Child and initialize a new one of the desired type. E.g. in
- OnActivate do:
-
- Child := TForm2.Create(Self);
- with Child do begin
- Parent := Self;
- Align := alClient;
- Visible := True;
- end;
-
- When you create a child page due to a tab change, do it in the
- same way just shown. Of course you'll need to use the main form
- to store any data about the state of the controls in a given
- child window, because the data will go bye-bye when the child
- is freed.
-
- ------------------------------------------------------------------------
-
- Q. How do you deselect one or more items in a listbox or combobox?
-
- A. Listbox1.ItemIndex := -1;
-
- ------------------------------------------------------------------------
-
- Q. Why is it that when I call a dialog window such as MessageBox()
- from within an event handler such as OnExit that the blinking
- cursor (the caret) disappears upon closing the dialog?
-
- A. This is a Windows behavior. Forcing an additional focus change
- (e.g., with ShowMessage) during an event associated with a focus
- change (e.g., OnExit) will cause Windows to become confused. It is
- Windows that is controlling the focus change, and it is Windows that
- becomes confused when you force a focus change in the middle of that
- process.
-
- ------------------------------------------------------------------------
-
- Q. Why do I get the exception 'EInvalidOperation: Cannot make a visalbe
- window modal' when I try to open a form with Showmodal? The form is
- not open yet.
-
- A. Make sure the form's Visible property is not being set to Ture at
- design-time or run-time.
-
- ------------------------------------------------------------------------
-
- Q. Why do I get the message 'Unable to load RPTSMITH.EXE' when I
- double click on the TReport componet on the form? It should
- bring up ReportSmith.
-
- A. Either the [ReportSmith] section is missing or incorrect in
- the DELPHI.INI file. Make sure that it specifies the correct
- path. e.g.
-
- [ReportSmith]
- ExePath=C:\RPTSMITH
-