
Here I'll try to give some tips to help general development of Delphi
programs. If you like them or have any tip to share, please e-mail
me.

Running
a DOS program and closing its window after running it
When you run a DOS program in Windows95, its window remains open until
closed by the user. To run a Dos program that closes its windows after
running, you must specify "command.com /c program" in the
command line. Using WinExec API function to run a program named progdos.exe,
the call should be:
WinExec("command.com /c progdos.exe",sw_ShowNormal);
If you wish that the program is run hidden from the user, the second
parameter must be sw_Hide. You must specify the .com extension, or the program will not run.
Changing
a TEdit text in its OnChange event
If you want to change a TEdit text in its OnChange event, it will fire
the event recursively until stack exhausts. To do this, you must set it
to NIL before changing its text and reassigning it after, like this:
procedure Edit1Change(Sender : TObject);
begin
Edit1.OnChange := NIL;
if Edit1.Text = 'Some Text' then
Edit1.Text := 'New Text';
Edit1.OnChange := Edit1Change;
end;
This tip works also with OnValidate events.
Shrinking
the executable
In Delphi 1.0, sometimes checking the Optimize for size and load
time checkbox, in Options/Project/Linker doesn't work (you get
a Disk full message, even with plenty of space). Delphi 1.0 comes with
a Dos program, W8LOSS, that does the same. To use, it you must type:
It will shrink your executable in about 20%, and will speed up loading
time.
Getting
current line and column from a memo
To get the current line and column from a memo you must use this:
With Memo1 do begin
Line := Perform(EM_LINEFROMCHAR,SelStart, 0);
Column := SelStart - Perform(EM_LINEINDEX, Line, 0);
end;
Changing
a menu font
To change a menu font, you must forget using Delphi's menu designer.
You must create the menu items using Api function AppendMenu, with flag
MF_OWNERDRAW, in the Form's OnCreate Event. Then you must use WM_MEASUREITEM
and WM_DRAWITEM to draw your menu options. Download
an example.
International settings
By default, Delphi gets its date/time, currency and numeric format from Control Panel's International settings.
This can lead to errors, when parsing dates, numbers or lists. To avoid these errors, you can set the constants defined in Delphi,
like DecimalSeparator, ShortDateFormat and others like this:
This will override the default settings assuring the correct values. To a complete list of these variables, look at Currency Formatting Variables in Delphi Help
Extracting icons from an executable
To extract icons from an executable, you must use ExtractIcon API function. It gets 3 parameters:
Instance - Instance of the application
FileName - Name of the executable. Must be a PChar
NumIcon - Number of the icon to be retreaved. If it's Word(-1), the function returns the number of icons in the executable.
Download an example.
How to Get Dos Environment
To get DOS Environment, you must use GetDosEnvironment API Function.It returns a PChar that can be parsed. Download an example.
Filtering and sorting tables in Delphi 1.0
To filter and sort a table in Delphi 1.0 you can use a QBE (Query by Example) file as the TableName TTable's property. This is useful to filter, sort or join tables, while still using the TTable component. QBE files can be created in Database Desktop.
Acessing DBNavigator buttons
The DBNavigator has a protected Buttons array that acesses its buttons. An inherited Navigator can acess them and change their properties. TBSNavigator does this to change their Enabled state or Glyph.
Making Enter key act as Tab
Packing tables
To pack (remove phisically all deleted records) from a Paradox table you must use this code
procedure ParadoxPack(Table : TTable);
var
TBDesc : CRTblDesc;
hDb: hDbiDb;
TablePath: array[0..dbiMaxPathLen] of char;
begin
FillChar(TBDesc,Sizeof(TBDesc),0);
with TBDesc do begin
StrPCopy(szTblName,Table.TableName);
StrPCopy(szTblType,szParadox);
bPack := True;
end;
Table.Open;
hDb := nil;
Check(DbiGetDirectory(Table.DBHandle, True, TablePath));
Table.Close;
Check(DbiOpenDatabase(nil, 'STANDARD', dbiReadWrite,
dbiOpenExcl,nil,0, nil, nil, hDb));
Check(DbiSetDirectory(hDb, TablePath));
Check(DBIDoRestructure(hDb,1,@TBDesc,nil,nil,nil,False));
Table.Open;
end;
To pack Dbase tables use this command
DBIPackTable(Table1.DBHandle,Table1.Handle,nil,nil,True);
Working with multiselect grids
Delphi 2.0 multiselect grids have an undocumented SelectedRows property, a TBookmark list.
You can use it with a code like this:
With DbGrid1 do begin
for i := 0 to Pred(SelectedRows.Count) do begin
DataSource.DataSet.Bookmark := SelectedRows[i];
{the dataset is positioned on the selection. Do your stuff}
end;
end;
Listing all open windows
To list (get) all open windows, you must use EnumWindows API function. It uses a callback function, that receives 2 parameters: a Window handle and a Pointer.
You can use it with a code like this (this code lists all open windows, even invisible ones in a listbox):
function EnumWindowsProc(Wnd : HWnd;Form : TForm1) : Boolean; Export;
{$ifdef Win32} StdCall; {$endif}
var
Buffer : Array[0..99] of char;
begin
GetWindowText(Wnd,Buffer,100);
if StrLen(Buffer) <> 0 then
Form.ListBox1.Items.Add(StrPas(Buffer));
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
EnumWindows(@EnumWindowsProc,LongInt(Self));
end;
Converting the first letter of an EditBox to uppercase
Doing incremental search in a Table
To do incremental search on a table, using a TEdit, you must put this code in the TEdit's OnChange Event:
procedure TForm1.Edit1Change(Sender: TObject);
begin
With Edit1 do
if Text <> '' then
Table1.FindNearest([Text]);
end;
Doing incremental search in a Query
To do incremental search in a Query, using a TEdit, you must put this code in the TEdit's OnChange Event (this works only in D2/D3):
procedure TForm1.Edit1Change(Sender: TObject);
begin
With Edit1 do
if Text <> '' then begin
Query1.Filter := 'code = '''+Edit1.Text+'''';
Query1.FindFirst;
end;
end;
Another way could be
procedure TForm1.Edit1Change(Sender: TObject);
begin
With Edit1 do
if Text <> '' then
Query1.Locate('code',Edit1.Text,[loPartialKey]);
end;
Creating non rectangular windows (D2/D3)
To create a non rectangular window, you must create a Windows Region and use the API function SetWindowRgn, like this (this works only in D2/D3):
var
hR : THandle;
begin
{creates an Elliptic Region}
hR := CreateEllipticRgn(0,0,100,200);
SetWindowRgn(Handle,hR,True);
end;
Tip collaboration by: Serkan Aksu
Detecting Windows Shutdown
To detect Windows Shutdown, you must trap WM_EndSession message. These steps should be taken:
Declare a message handling procedure in your Form's Private section:
procedure WMEndSession(var Msg : TWMEndSession); message WM_ENDSESSION;
Add the procedure to the implementation section of your Unit:
procedure TForm1.WMEndSession(var Msg : TWMEndSession);
begin
if Msg.EndSession = TRUE then
ShowMessage('Windows is shutting down ' + #13 + 'at ' +
FormatDateTime('c', Now));
inherited;
end;
Tip submitted by Steve Harman
Moving the mouse pointer
To move the Mouse pointer with no user's action, you can use a timer and put the following code in it's OnTimer event:
procedure TForm1.Timer1Timer(Sender: TObject);
var
pt:tpoint;
begin
getcursorpos(pt);
pt.x := pt.x + 1;
pt.y := pt.y + 1;
if pt.x>=screen.width-1 then setcursorpos(0,pt.y);
if pt.y>=screen.height-1 then setcursorpos(pt.x,0);
end;
Tip submitted by Serkan Aksu
Positioning the caret in a line in a memo or RichEdit
To position the caret in a line in a Memo or RichEdit you must use this:
With Memo1 do
SelStart := Perform(EM_LINEINDEX, Line, 0);
Moving forms with no caption
To move a form with no caption, you must override WM_NCHITTEST message, like this:
type
TForm1 = class(TForm)
public
procedure WMNCHitTest(var M: TWMNCHitTest); message WM_NCHitTest;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
inherited;
if M.Result = htClient then {if the mouse clicked on the form}
M.Result := htCaption; {make windows think that mouse has been clicked on caption}
end;
Tip submitted by Serkan Aksu
Right justifying menu items
To justify menu items on the right side of the main menu bar, you must do like this:
{It will right justify all menu items to the right of the one selected}
procedure SetJustify(Menu: TMenu; MenuItem: TMenuItem; Justify: Byte);
{$IFDEF WIN32}
var
ItemInfo: TMenuItemInfo;
Buffer: array[0..80] of Char;
{$ENDIF}
begin
{$IFDEF VER80}
MenuItem.Caption := Chr(8) + MenuItem.Caption;
{$ELSE}
ItemInfo.cbSize := SizeOf(TMenuItemInfo);
ItemInfo.fMask := MIIM_TYPE;
ItemInfo.dwTypeData := Buffer;
ItemInfo.cch := SizeOf(Buffer);
GetMenuItemInfo(Menu.Handle, MenuItem.Command, False, ItemInfo);
if Justify = 1 then
ItemInfo.fType := ItemInfo.fType or MFT_RIGHTJUSTIFY;
SetMenuItemInfo(Menu.Handle, MenuItem.Command, False, ItemInfo);
{$ENDIF}
end;
Tip submitted by Eddie Shipman
Display and Change video resolutions
To display available video modes, you must use the API function EnumDisplaySettings: it gets all display setting modes available.
To change modes, you must use ChangeDisplaySettings, that changes the video resolution and color depth.
Download an example.
Detecting when the mouse is over a component
When the mouse enters the area of a component, Delphi sends the CM_MouseEnter message. When it leaves, Delphi sends a CM_MouseLeave message. Treating this two messages, you can detect if the mouse is over the component. The Fly-Over label component shows this technique.
Detecting Windows shutdown
When Windows is shutting down, it sends a WM_QueryEndSession to all open applications. To detect (and prevent shutdown), you must define a message handler to this message. Put this definition on the private section of the main form:
procedure WMQueryEndSession(var Msg : TWMQueryEndSession); message WM_QueryEndSession;
And put this method in the implementation section of the unit:
procedure TForm1.WMQueryEndSession(var Msg : TWMQueryEndSession);
begin
if MessageDlg('Close Windows ?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then
Msg.Result := 0
else
Msg.Result := 1;
end;
Drawing with different line types
Windows allows to draw lines where each pixel is another shape or drawing with LineDDa function. It needs a callback function that is called when each pixel must be drawn. There you can put the drawing routines. This routine draws a rectangle every 4 pixels:
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
public
DrawNow : Integer;
end;
var
Form1: TForm1;
procedure DrawPoint(x,y : Integer;lpData : LParam); stdcall;
implementation
{$R *.DFM}
procedure DrawPoint(x,y : Integer;lpData : LParam);
begin
with TObject(lpData) as TForm1 do begin
if DrawNow mod 4 = 0 then
Canvas.Rectangle(x-2,y-2,x+3,y+3);
Inc(DrawNow);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DrawNow := 0;
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
LineDDA(0,0,Width,Height,@DrawPoint,Integer(Self));
end;
Calling Windows DialUp Connection Dialog
To call Windows DialUp Connection Dialog, you can use WinExec, like this:
procedure TForm1.Button1Click(Sender: TObject);
begin
winexec(PChar('rundll32.exe rnaui.dll,RnaDial '+Edit1.Text),sw_show);
end;
Tip submitted by Ronaldo R. Campos
Acessing Protected Members of an Object
Usually, you can't access protected members of an object. But Delphi let you access protected members if the object is defined in the same unit. So you can define a derived object and typecast where you want to use the protected member. It's something like this:
THackControl = class(TCustomEdit)
end;
After defining this class, you can access all protected members of TCustomEdit, with objects of derived classes with a code like this:
THackControl(MyEdit).Color := clBlack;
Hiding Minimized MDI Child Windows
To hide minimized MDI child windows, you must trap its WM_Size message, like this:
type
TForm1 = class(TForm)
public
procedure WMSize(var M : TWMSIZE);Message WM_Size;
end;
implementation
procedure TForm1.WMSize(var M:TWMSIZE);
begin
if M.SizeType=Size_Minimized then
showwindow(Handle,Sw_Hide);
end;
Tip submitted by Serkan Aksu
Hiding and showing the Windows Taskbar
To hide the Windows Taskbar you must use a code like this:
procedure TForm1.Button1Click(Sender: TObject);
var
hTaskBar :Thandle;
begin
hTaskBar := FindWindow('Shell_TrayWnd',Nil);
ShowWindow(hTaskBar,Sw_Hide);
end;
To Show the Windows Taskbar, you must use this code:
procedure TForm1.Button2Click(Sender: TObject);
var
hTaskBar :Thandle;
begin
hTaskBar := FindWindow('Shell_TrayWnd',Nil);
ShowWindow(hTaskBar,Sw_Normal);
end;
Tip submitted by Huescli Serra Lima
Paradox Password in code
To give the password of a Paradox table in code, you can use this code:
procedure TForm1.FormCreate(Sender: TObject);
begin
Session.AddPassWord('MyPass');
Table1.Acive := True;
end;
Tip submitted by Huescli Serra Lima
Executing default action of an Ole Container
To execute the default action of an Ole Container (open a Word or Excel document or run a Powerpoint presentation), you can use this code:
procedure TForm1.Button1Click(Sender: TObject);
begin
OleContainer1.DoVerb(ovprimary);
end;
Tip submitted by Huescli Serra Lima

If you want to be notified of updates, please join the mailing list
Back to main page