Forms

Delphi Applications without Forms?

From: bpeck@prairienet.org (Bob Peck)

You bet! First, select File|New Project and choose "CRT Application" from the Browse Gallery dialog. This will provide you with a project that is still a Windows program, but WriteLn, ReadLn will be allowed in a Window but work like they did in DOS. If you wish, you can remove the WinCrt unit from the uses statement (if no user input/output is required, but is nice for debugging).

I've done this before just to see how small an app can be and I've been able to create a simple EXE (it just beeps) that is only 3200 bytes or so in size! Try to do that in C++ these days!

BTW, these "formless" apps are still Windows applications, so they can still call the Windows API routines. You'll just need to add WinProcs, WinTypes to your uses clause. You'll probably also want to add SysUtils and any other unit you find yourself needing.

Showing own logo on start-up

From: "Mark R. Holbrook" <markh@sysdyn.com>

It's pretty simple.

Create a form and put the logo on it using a Timage component. My example below assumes you have created a logo form called "logoform" Go to your project options and set the form to NOT be autocreated.

Then in your PROJECT.DPR file just after the begin statement do something like the following:


   logoform := TLogoform.Create(nil);
   logoform.Show;            { NOTE! show!   NOT showmodal }

   .
   . { Do other app startup stuff here like open databases etc... }
   .

   .  { Just after the block of code that creates all your forms and
         before the Application.Run statement do: }

   logoform.Hide;
   logoform.Release;

This will display your logo form until you actually start the app running.

Moving a form without a caption bar

From: mger@sbox.tu-graz.ac.at (Matthias Gerstgrasser)

The following is from DKBS Helpfile (Delphi Knowledge Base System), they state, that this is one of Borland's TI's:

Q: How can I make a form move by clicking and dragging in the client area instead of on the caption bar?

A: The easiest way to do this is to "fool" Windows into thinking that you're actually clicking on the caption bar of a form. Do this by handling the wm_NCHitTest windows message...


type
  TForm1 = class(TForm)
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;
  end;

var
  Form1: TForm1;

implementation
{$R *.DFM}

procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
  inherited;                    { call the inherited message handler }
  if  M.Result = htClient then  { is the click in the client area?   }
    M.Result := htCaption;      { if so, make Windows think it's     }
                                { on the caption bar.                }
end;

Preventing the user from resizing my window vertically

From: Bill Dekleris <quasar@prometheus.hol.gr>

You must trap WM_GETMINMAXINFO message:

in your form's class declaration put this :


procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;

and in the implementation section :


procedure TMyForm.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
begin
   { ---------------------------------------------}
   { Put your numbers in place of                 }
   { MIN_WIDTH, MIN_HEIGHT, MAX_WIDTH, MAX_HEIGHT }
   {                                              }
   { To allow only horizontal sizing, put         }
   { form's 'Height' property in place of MIN_HEIGHT, MAX_HEIGHT }
   { ---------------------------------------------}
   Msg.MinMaxInfo^.ptMinTrackSize := Point(MIN_WIDTH, MIN_HEIGHT);
   Msg.MinMaxInfo^.ptMaxTrackSize := Point(MAX_WIDTH, MAX_HEIGHT);
   inherited
end;

It should work fine.

Hack: Want VCL controls in a form's title bar caption area?

From: "James D. Rofkar" <jim_rofkar%lotusnotes1@instinet.com>

Here's the trick:

Treat your controls like they belong in a separate modeless dialog that just so happens to track the movement and resizing of your main form. In addition, it always appear over the main form's caption area.

This said, here's a simple hack that involves 2 forms and a drop-down listbox. After running this program, the drop-down listbox will appear in the Main form's caption area. Two key issues are: 1) trapping the Main form's WM_MOVE message; and 2) returning focus back to the Main form after users press any focus-grabbing controls (like a TComboBox, TButton, etc.)

[FYI, I'm using 32-bit Delphi 2.0 Developer under Win95 -- even though this technique should work for all versions of Delphi]

Here's the source for the Main form:


   unit Unit1;

   interface

   uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
     Dialogs,  StdCtrls;

   type
     TForm1 = class(TForm)
       procedure FormResize(Sender: TObject);
       procedure FormShow(Sender: TObject);
       procedure FormHide(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
       procedure WMMove(var Msg: TWMMove); message WM_MOVE;
     end;

   var
     Form1: TForm1;

   implementation

   uses Unit2;

   {$R *.DFM}

   procedure TForm1.FormResize(Sender: TObject);
   begin
        with Form2 do
           begin
           {Replace my magic numbers with real SystemMetrics info}
           Width := Form1.Width - 120;
           Top := Form1.Top + GetSystemMetrics(SM_CYFRAME);
           Left := ((Form1.Left + Form1.Width) - Width) - 60;
           end;
   end;

   procedure TForm1.FormShow(Sender: TObject);
   begin
        Form2.Show;
   end;

   procedure TForm1.FormHide(Sender: TObject);
   begin
        Form2.Hide;
   end;

   procedure TForm1.WMMove(var Msg: TWMMove);
   begin
        inherited;
        if (Visible) then FormResize(Self);
   end;

   end.

Here's the source for the pseudo-caption area form. This is the form that contains the VCL controls you wish to place in the Main form's caption area. Essentially, it's a modeless dialog with the following properties:


   Caption='' {NULL string}
   Height={height of caption area}
   Width={width of all controls in form}
   BorderIcons=[] {none}
   BorderStyle=bsNone
   FormStyle=fsStayOnTop

Anyhow, here's the source for Form2:


   unit Unit2;

   interface

   uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls;

   type
     TForm2 = class(TForm)
       ComboBox1: TComboBox;
       procedure FormCreate(Sender: TObject);
       procedure ComboBox1Change(Sender: TObject);
       procedure FormResize(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

   var
     Form2: TForm2;

   implementation

   uses Unit1;

   {$R *.DFM}

   procedure TForm2.FormCreate(Sender: TObject);
   begin
        Height := ComboBox1.Height - 1;
        Width := ComboBox1.Width - 1;
   end;

   procedure TForm2.ComboBox1Change(Sender: TObject);
   begin
        Form1.SetFocus;
   end;

   procedure TForm2.FormResize(Sender: TObject);
   begin
        ComboBox1.Width := Width;
   end;

   end.

The project file (.DPR) is fairly straightforward:


   program Project1;

   uses
     Forms,
     Unit1 in 'Unit1.pas' {Form1},
     Unit2 in 'Unit2.pas' {Form2};

   {$R *.RES}

   begin
     Application.Initialize;
     Application.CreateForm(TForm1, Form1);
     Application.CreateForm(TForm2, Form2);
     Application.Run;
   end.

That's it!

Although some Delphi book authors state:

"You can't place a Delphi component on the title bar, so there's literally no way to put a button there."

you can at least "fake" the illusion...

Storing TForm and/or its properties in a BLOB

From: Oliver.Bollmann@t-online.de (Oliver Bollmann)

Hallo, here are examples you need, I hope:


procedure SaveToField(FField:TBlobField;Form:TComponent);
var
  Stream: TBlobStream;
  FormName: string;
begin
  FormName := Copy(Form.ClassName, 2, 99);
  Stream := TBlobStream.Create(FField, bmWrite);
  try
    Stream.WriteComponentRes(FormName, Form);
  finally
    Stream.Free;
  end;
end;

procedure LoadFromField(FField:TBlobField;Form:TComponent);
var
  Stream: TBlobStream;
  I: integer;
begin
  try
    Stream := TBlobStream.Create(FField, bmRead);
    try
      {delete all components}
      for I := Form.ComponentCount - 1 downto 0 do
        Form.Components[I].Free;
      Stream.ReadComponentRes(Form);
    finally
      Stream.Free;
    end;
  except
    on EFOpenError do {nothing};
  end;
end;

Removing icon on taskbar

From: AVONTURE Christophe <Christophe.AVONTURE@is.belgacom.be>


 ShowWindow (Form1.Handle, SW_HIDE);

How can I hide the form caption bar??

From: "James D. Rofkar" <jim_rofkar%lotusnotes1@instinet.com>

First, override the "CreateParams" method of your Form, by declaring this in either your Form's protected or public section:


   procedure CreateParams(var Params: TCreateParams); override;

Then, in the actual CreateParams() method, specify something like this:


   procedure TForm1.Createparams(var Params: TCreateParams);
   begin
        inherited CreateParams(Params);
        with Params do
           Style := (Style or WS_POPUP) and (not WS_DLGFRAME);
   end;

Hopefully, you'll provide some UI mechanism for moving and closing the window.

Floating toolbar - here's some code to do it

From: ao@atlas.sto.foa.se (Anders Ohlsson)

Someone asked for some code to make a form with no title bar moveable, kind of like a floating toolbar, for example FreeDock. Actually, for some of the stuff in here I spied on the FreeDock sources...

This requires the use of some WinAPI functions. All WinAPI functions are however available at a touch of a key (F1 - OnLine Help)...

Here's some code that does this (about 100 lines)...

To make this work like intended:

OR start a new project, make the form's borderstyle bsNone, add a panel, set the border style of the panel to bsSingle, add another panel with some caption, add a button that says 'toggle title bar', cut out the below code and insert it were it should be, enable the panel's three event handlers (MouseDown, MouseMove, MouseUp), enable the button's event handler (Click). Hope I didn't forget anything... ;-) It's done faster in Delphi than it's written here... ;-)


unit Unit1;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Panel1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    OldX,
    OldY,
    OldLeft,
    OldTop   : Integer;
    ScreenDC : HDC;
    MoveRect : TRect;
    Moving   : Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then begin
    SetCapture(Panel1.Handle);
    ScreenDC := GetDC(0);
    OldX := X;
    OldY := Y;
    OldLeft := X;
    OldTop := Y;
    MoveRect := BoundsRect;
    DrawFocusRect(ScreenDC,MoveRect);
    Moving := True;
  end;
end;

procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if Moving then begin
    DrawFocusRect(ScreenDC,MoveRect);
    OldX := X;
    OldY := Y;
    MoveRect := Rect(Left+OldX-OldLeft,Top+OldY-OldTop,
                     Left+Width+OldX-OldLeft,Top+Height+OldY-OldTop);
    DrawFocusRect(ScreenDC,MoveRect);
  end;
end;

procedure TForm1.Panel1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then begin
    ReleaseCapture;
    DrawFocusRect(ScreenDC,MoveRect);
    Left := Left+X-OldLeft;
    Top := Top+Y-OldTop;
    ReleaseDC(0,ScreenDC);
    Moving := False;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  TitleHeight,
  BorderWidth,
  BorderHeight : Integer;
begin
  TitleHeight := GetSystemMetrics(SM_CYCAPTION);
  BorderWidth := GetSystemMetrics(SM_CXBORDER)+GetSystemMetrics(SM_CXFRAME)-1;
  BorderHeight := GetSystemMetrics(SM_CYBORDER)+GetSystemMetrics(SM_CYFRAME)-2;
  if BorderStyle = bsNone then begin
    BorderStyle := bsSizeable;
    Top := Top-TitleHeight-BorderHeight;
    Height := Height+TitleHeight+2*BorderHeight;
    Left := Left-BorderWidth;
    Width := Width+2*BorderWidth;
  end
  else begin
    BorderStyle := bsNone;
    Top := Top+TitleHeight+BorderHeight;
    Height := Height-TitleHeight-2*BorderHeight;
    Left := Left+BorderWidth;
    Width := Width-2*BorderWidth;
  end;
end;

end.

Comments

From: Steve Teixeira

I have one comment on the FloatWin sample, though: it's *much* more complicated than it needs to be. All you have to do is handle Windows' wm_NCHitTest message. Here is some code I wrote for a Borland Tech Info document that does the same thing.
unit Dragmain;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
  inherited;                    { call the inherited message handler }
  if  M.Result = htClient then  { is the click in the client area?   }
    M.Result := htCaption;      { if so, make Windows think it's     }
                                { on the caption bar.                }
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Close;
end;

end.

Programming for different resolutions in Delphi 2.0

You need to download:

Ti2861 - Form display with different screen resolutions.

from the Delphi Technical Support area of our web site at www.borland.com.


Please email me and tell me if you liked this page.

This page has been created with