Forms / Dialogs

Forms / Dialogs

Different dialogs from form template
Dialogs, those modal considering the whole system
Multi-form Menus
Dragging windows without titlebars
Close an application on deactivate
Getting the name of a form
Different Resolutions - different font sizes
Form width
Positioning self-created forms
Procedure to Wrap dialog box with an object
Running without a form
Transparent splash screen
Form.TForm.Create(???)
Does this form exist
Freeing form
How do you keep the user from resizing a form
Creating a form with a width < 102
Disable ALT-F4
Dialog box title
Forms / Scaled
Set focus while modal dialog is open
Overriding ESC-key on a Form
Destroy a Modal Form on Deactivate
Adding BorderIcons to a form
Closing a modal form
Event for Form move
Copy the screencontents into a form
Putting Forms into a stream
Forms - Dragging without clicking the caption bar
Making apps show minimized
Transparent window
Controlling form maximization
Making a form selectable without the main form
Scrolling forms with PgUp and PgDn
Creating own hotkeys
Hiding a form's title bar
Using an alternate main form


Different dialogs from form template

Question


My main problem is that i am using different 'dialogs' from the forms

template. Where i have used a form i can amend the code to create it at

runtime ie when needed with the following code

   formx := tformx.create(appliaction);

   formx.showmodal;

   formx.free;

However if i use the same code on the form using the form name/aliasname

the form does not show.



Answer


A:

try this code:



	  Application.CreateForm(TFormX, FormX);

	  FormX.ShowModal;

	  FormX.Free;



don't forget that the visible property of this form have to be false

when it is created, if it isn't you will get an error when you want

to show it modal.




Dialogs, those modal considering the whole system

Question


with showmodal i show a dialog, which is modal considering the app. how

can i show a dialog, which is modal to the whole system (no switches to other

tasks should be allowed)?

i want to show dialogs, which comes on the top of all windows if the app

running at background. how to realize this?



Answer


A:

Check out API-function SetSysModalWindow

Check out API-function BringWindowToTop



A:

If you just want a simple dialog with a bit of text, an optional

icon and some buttons, use MessageBox in WinProcs

and use MB_SYSTEMMODAL in the TextType parameter.



A:

Use the SetSysModalWindow() Windows API function.  The following code

snippet demonstrates its use.  There can be only one system-modal window at

a time, and that handle is returned by SetSysModalWindow().  I suggest that

you save that return value and then reset it when you are finished, as

demonstrated below.



procedure TForm1.Button1Click(Sender: TObject);

var

   x : word ;

begin

     x := SetSysModalWindow(AboutBox.handle) ;

     AboutBox.showmodal ;

     SetSysModalWindow(x) ;

end;




Multi-form Menus

Question


I have a project that has multiple NON-MDI forms. The problem I am having is that if I put a menu on a form other than the form designated as the "Main Form," it does not work correctly. The menu on the main form pops up whenever you hit the Alt key. If the main form does not have a menu, the program just beeps at you obnoxiously

and tries to switch focus back and forth.

Can non-Main form's have menus or not? If so, how do I convince my APP to let the user access them with the alt key.



Answer


A:

In you "Main Form" you need to catch key events and pass them to the

NON-MDI forms by calling their proceedures, ie. using the NON-MDI forms

event handlers.  If you like this idea then can use the onkeydown event in

the "Main Form" to check to see if the user has pressed an ALT key

combination before calling the NON-MDI forms proceedure.  Don't forget to 

add the NON-MDI forms unit to the USES section of the "Main Form". I 

assumed you probably already have done this anyhow.

If you don't like that idea, then the only other way I know is to set the 

focus to the NON-MDI form before the user presses a key.




Dragging windows without titlebars

Question


I want to know how to move a window by dragging the components on the form or the form itself because I want to create a window without a title bar.

(e.g. move the window by dragging a panel on the form)



Answer


A:

Here is how you do it...



{most basic form definition}

  TForm1 = class(TForm)

  private

    procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;

  end;



{... and this is the actual message handler procedure}

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;



It works by tricking Windows into thinking that the mouse is in the forms

caption area. This may cause problems since the mouse is always considered to

be in the caption area whenever it is in client area but it is a very elegent

solution because the forms border changes to the standard fuzzy outline while

it is being dragged. There may be another message that you can trap which

produces the same result if this doesn't quite work for you.



A:

1. Disable all BorderIcons for the form.

2. Make sure the caption is an empty string.

3. BorderStyle = bsNone

4. Override the form's CreateParams procedure as shown below



type

   TForm1 = class(TForm)

{       ...

	a bunch of stuff

	...}

      protected

	procedure CreateParams(var Params : TCreateParams); override;

      public

   end;



{... other stuff ...}



implementation



{...}



procedure TForm1.CreateParams(var Params: TCreateParams);

begin

   inherited CreateParams(Params);

   with Params do

      Style := Style or ws_Border or ws_ThickFrame;

end;



{...}



end.



A:

Var

   Moving  : Boolean;

   OldX, OldY : Integer;

...............

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, Y: Integer);

begin

     If Button = mbLeft Then    {only interested in left button}

     Begin

	OldLeft := X;           {Store current position}

	OldTop := Y;

	Moving := True;

     End;

end;



procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,

  Y: Integer);

begin

	{If required move the window relative to its original position}

   If Moving Then Self.SetBounds

(Self.Left + X - OldLeft, Self.Top + Y - OldTop, Self.Width,

Self.Height);



end;



procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, Y: Integer);

begin

     If Button = mbLeft Then

	  Moving := False;              {Stop Movement}

end;



Remember to assign these methods to each control on your form eg.



Self.Panel1.OnMouseDown := Self.OnMouseDown;




Close an application on deactivate

Question


How to close an application if it will deactivated?



Answer


A:

Try the following code:

procedure TForm1.AppDeactivate(Sender: TObject);

begin

  close;

end;



procedure TForm1.FormCreate(Sender: TObject);

begin

  Application.OnDeactivate := AppDeactivate;

end;




Getting the name of a form

Question


I'm trying to get the name of a form at run time.

Answer


A:

If you use the ClassName property like this.



   with Sender as TForm do

      Label1.Caption := copy(ClassName,2,length(ClassName)-1);



This will give the desired effect without extra coding in the Form's create

method.



A:

'Sender' may well not be the form in question, and your program will throw an

exception on the invalid typecast. I'm not sure under which conditions (if

any) Sender actually would be the Form itself.



Anyway, you can protect yourself by bracketing the call with a exception

handler or just a simple test, like so:

  If Sender is TForm then

    Label1.Caption := (Sender as TForm).Name ;



If what you're trying to accomplish is the following:

  Label1.Caption := Form1.Name ;



That's a whole different kettle of fish. I've read a lot of complaints

that this or that property of a Form isn't available at run time, most

of the cases seem to be linked to a misapprehension regarding class

initialization. If you read the Delphi docs carefully, you'll note that

setting a property in the Object Inspector does NOT automatically set

that property for run-time purposes.  The answer to THIS situation is to

explicitly set the property (.Name in this case) in the Form's .Create

method. So, some code like the following WILL work:



procedure TForm1.Create( Sender : TObject ) ;

begin

  Form1.Name := 'Form1' ;

end ;



procedure TForm1.Button1Click( Sender : TObject ) ;

begin

  Label1.Caption := Form1.Name ;

end ;



A:

var

  TC: TComponent;

begin

  TC := label1.Owner;

  label1.Caption := TC.ClassName;

end;



A:

I added a button to my form and in its event handler I put:



	name := 'AName';



Then after clicking on the button, I could then click on the form and

the label's caption changed to 'AName'.

The solution is to define the property Name in the form's create event.

I.E. if you have a form named MyForm then in its OnCreate event you

should have:



	name := 'MyForm';



This will solve your problem, but I agree its a little abnoxious.




Different Resolutions - different font sizes

Question


A user with a different resolution than yours, because the font size, get

your form with another appearance, _IF_ you didn't set fpVariable in the font

properties.

But if you create a maximized form, this doesn't work!

Answer


A:

I have had a great deal of bother with this subject and I have done some

experimentation now.



The font fpVariable thing is important, but also are some other properties

that are important.



1. I got stupid results on changing resolution until I changed the font

size to be defined in pixels instead of points.  You can set font.height and

you can set font.size. I find things are much better if you specify

font.height because it is then defined in pixels and everything stays in

proportion if the size of a pixel changes.



Also you will find that the default font can't be used below a certain

height. If you change to the MS sans-serif font instead of SYSTEM, things

are better.



2.  There is a property for a form that is called "scaling" (I think, from

memory). I find it better to have this turned off. Apparently if it is

switched on, Delphi or Windows tries to scale everything appropriately when

the size of the form changes. I found that this is quite good at wrecking

the relative positions of things on a form so I turn it off.



When it is off and a form is maximised, you will find that your components

tend to be in the top left quadrant of the screen.  Where this is not

desirable I find out the screen resolution (Screen.Height and Screen.Width)

and make appropriate run time changes to the top and left properties of

components before the form appears (in OnCreate method).



On the whole, though, turning scaling off and using pixel sizes for fonts

instead of point sizes gives reasonable results.


Form width

Question


I want to create a Form with the width set to 130, however when I do

this either by trying to set the property at design time or by

setting the width in FormCreate ir always returns to 142.

Answer


A:

Could it because of some components you have on your forms?

Try creating a _new_ form with no components and set it to 130 and see if

the same thing happens.



A:

You may be running up against a Windows behavior in which it sets a default

minimum width. If so, you can try creating a message handler for

wm_GetMinMaxInfo to set the minimum width of a window. The way this message

works is by passing a pointer to a structure (in lParam). You can also set

the maximum size of a window, and the maximized size of a window, and the

position of the window when maximized. Here is an example of how to use it

to only change the minimum width:



Add this to the private declaration of your TForm descendant:



    procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); message

wm_GetMinMaxInfo;



and this would be the implementation:



procedure TForm1.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);

begin

  Msg.MinMaxInfo^.ptMinTrackSize.x := 130;

end;



Note that Windows 95 is a little different than Windows 3.1 on minimum window

widths.  Since Win95 adds new buttons in the caption bar of windows in the

case that you specified using either a Minimize or Maximize button to be in

the caption, the minimum width in that case is a bit more than in Windows

3.1.  Also, it might be a bit different depending on the size of the caption

font.


Positioning self-created forms

Question


In my MainForm (Form1) I create another form, the position of which I want

to control. Form1 is a standard blank form, Form2 too but with DialogBox

style (but I have for sure tested all combinations of borderstyles etc).



Now, with a simple "child" form (no MDI!) code like



procedure Form1.Button1Click(Sender: TObject);

begin

  Form2 := TForm2.Create(self); { from within Form1 }

  with Form2 do begin

    Top  := Form1.Top + somevalue;

    Left := Form1.Left + someothervalue;

    ShowModal;

    Free;

  end;

end;



which works as expected.

Answer


A:

Delphi How-To book published by the Waite Group:

unit Runtime1;  { How-To 1.6 }



interface



uses

  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

  Forms, Dialogs, StdCtrls;



type



  TNewForm = class(TForm)

    NewEdit: TEdit;

    NewButton: TButton;

    procedure NewButtonClick(Sender: TObject);

  end;



  TForm1 = class(TForm)

    Button1: TButton;

    procedure Button1Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;



var

  Form1: TForm1;



implementation



{$R *.DFM}



{ OnClick handler for generated forms }

procedure TNewForm.NewButtonClick(Sender: TObject);

begin

  NewEdit.Text := 'Hi!';

end;



{ Generates and shows form from scratch }

procedure TForm1.Button1Click(Sender: TObject);

var

  NewForm: TNewForm;

begin

  { Create new form }

  NewForm := TNewForm.CreateNew(Application);

  { Set its properties }

  with NewForm do

  begin

    Top := 140;

    Left := 220;

    Width := 435;

    Height := 300;

    Caption := 'Runtime!';

    { Create new edit component }

    NewEdit := TEdit.Create(NewForm);

    { Set its properties }

    with NewEdit do

    begin

      Parent := NewForm;

      Left := 153;

      Top := 40;

      Width := 121;

      Height := 29;

      TabOrder := 1;

      Text := 'Edit1';

    end;

    { Create new button component }

    NewButton := TButton.Create(NewForm);

    { Set its properties }

    with NewButton do

    begin

      Parent := NewForm;

      Left := 153;

      Top := 176;

      Width := 121;

      Height := 33;

      TabOrder := 0;

      Caption := 'Change Edit';

      { Wire the component to OnClick handler }

      OnClick := NewButtonClick;

    end;

    Show;

  end;

end;



end.

In fact, they set the coordinates but they don't try to give some new

values. Moreover, couldn't you try the poScreenCenter property, only to see

if it could work?



Another opportunity would be to store in an Ini file values for your

positions, but you probably already tought about it.


Procedure to Wrap dialog box with an object

Question


I would like to create an object that has contained in it a dialog box.

The effect I am looking for is similiar to the FileOpen/Save dialogs, where you

set/get properties, then call an Execute method.

Answer


A:

I would go for a new form, Dialog style, fill in the necessary components,

and use it roughly like



  with TMyForm.Create(self) do begin

    Parent := Self;

    MyExecute(inParam, outParam);

    Release;

  end;



where MyExecute() would do the Show[Modal] and other things


Running without a form

Question


Is it possible to run a Delphi application without creating a(ny) form?

Answer


A:

Yes, using the project manager window, you can Remove the Form which is created

automatically when you start a new project.



Additionally (to get the .exe down to a reasonable size) you can remove the

"Application.Run" statement and the "uses Forms" from the project source.



Obviously, you will then have to add _some_ functionality to the application

in the Project Source (or provide it in a separate unit, and call one or more

of the routines in that unit from the Project Source).


Transparent splash screen

Question


It's splash screen is a circle, instead of the normal square. Everything behind

the circle (ie. what would normally be covered by the square) was visible.



Does anyone have any idea how they did this, or how I could do something

similar?

Answer


A:

Get the DC of the Screen and link it to a Canvas. Use the Canvas as you

would a forms canvas. Free the DC.


Form.TForm.Create(???)

Question


I have some questions about creating a form,

when and/or why do I use code line 1,2,3 or 4????

(MainForm and NameOnForm are FormStyle = fsNormal).



Procedure MainForm.BtnOpenFormClick(Sender: TObject);

Begin

  1) NameOnForm:=TNameOnForm.Create(APPLICATION);

  2) NameOnForm:=TNameOnForm.Create(NAMEONFORM);

  3) NameOnForm:=TNameOnForm.Create(SELF);

  4) NameOnForm:=TNameOnForm.Create(???????????);

     NameOnForm.ShowModal;

     NameOnForm.Free;

end;

Answer


A:

Don't use (2)!  You'll either GPF or, if this is a second instance of

NameOnForm you'll lose your pointer to the first.



My understanding of how (1) and (3) differ is: For a showModal, (1)

and (3) are equivalent.  For a show, (1) would keep nameOnForm open

until the application is closed (or until the user closes

NameOnForm), while (3) would close nameOnForm when mainForm is

closed.


Does this form exist

Question


How can I check to see if a form exists yet or not?  I have a button that

creates a subform and displays it. When the user clicks on close it does NOT

destroy it but just hides it. If the button is click again, I want to show

the form, not create a new instance. How can I tell if the form has been

created or not??

Answer


A:

Normally, dynamically instantiated  forms (or subforms in this case) are

created with a statement like...



        frmNewForm := TNewForm.Create( owner );



To achive what you have asked for, I can think of 3 possible solutions.

1) declare frmNewForm as a global var hence you can code:

        IF frmNewForm = NIL THEN

                frmNewForm := TNewForm.Create( owner );

        frmNewForm.Show;



or for those with an aversion to global vars



2) Find the refernce to frmNewForm that was saved in the components list of

the owner when TForm.Create( owner ) was called.

In most cases this will be the components array property of the main form.



3) If you do not have a main form that you want to be the owner of the

subform then use the TAppllication components CreateForm( TForm, refernce )

method. Later when you need to refer to the subform you can scan the

components array property of you application object. Find the form

by component name and retrieve the required reference.



A:

One important point, if you do release the object, you should set the

pointer to nil yourself.  Otherwise you may get a GPF next time round.



          frmNewForm.Release;

          frmNewForm := nil;



A:

If you specify the form's owner as 'Application' when you create it, you

can then iterate through Application's components to check if your form

still exists.



In order to do this, you can create the form either of these ways:



    Application.CreateForm(TSubForm, SubForm);

                - or -

    SubForm := TSubForm.Create(Application);



Then, you can check for your form's existence by iterating through 

Application's components:

     

    for i := 0 to Application.ComponentCount-1 do begin

        if Application.Components[i] = SubForm then ... {form exists};

     

     

Notes:

------

1. If you use 'Self' instead of 'Application' when creating the form, the

   form will not be a component of Application, so it won't be found when 

   you iterate through Application's components.

     

2. Instead of iterating through Application.Components, you could use

   'Application.FindComponent' *if* you've assigned a name to the form 

   (e.g., SubForm.Name := 'SubForm';) after you've created it.  

   'FindComponent' searches the Components array by *name*, and forms you 

   create are NOT given a name until you assign one.

     

3. Testing for a form's existence by using something like

   'if SubForm = nil' will NOT work UNLESS you specifically assign nil to 

   SubForm after you 'Free' it.  Delphi does NOT assign nil to forms when 

   it frees them.


Freeing form

Question


Am I right in believing that when a form is not visible it frees its

resources? Or do I have to Destroy it. How would i do that whithout

closing the app.

Answer


A:

        When a form isn't visible it is does set its resources free.

        What you need is to create it at run time.

        Use Release method, not Free.





Try this:



unit Unit1;



interface



uses

  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

  Forms, Dialogs, StdCtrls;



type

  TForm1 = class(TForm)

    Button1: TButton;

    Button2: TButton;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

  private

    { Private declarations }

  public

     Form2: TForm;

    { Public declarations }

  end;



var

  Form1: TForm1;



implementation



{$R *.DFM}



procedure TForm1.Button1Click(Sender: TObject);

begin

  if Form2 <> nil then

  begin

    Form2.Release;

    Form2:= nil;

  end;

end;



procedure TForm1.Button2Click(Sender: TObject);

begin

  if Form2 = nil then

  begin

    Form2 := TForm.Create(Application);

    Form2.Show;

  end;

end;



end.



[Francisco Torres, ftorres@cenpes.petrobras.gov.br]



A:

- In your main don't use this:



begin

Application.Create(myForm);

Application.Run;

end.



- But this:



begin

myForm := TmyForm.Create(Application);

		{ insert here what you want } 

myForm.Show;	{ ... or myForm.ShowModal }

		{ insert here what you want } 

myForm.Hide;	{ ... if you want to hide it }

		{ insert here what you want } 

myForm.Free;

end.



- You can "Create" and "Free" forms when you want and many times you want.



Remember to free-up all forms before ending your app!


How do you keep the user from resizing a form

Question


We want to prevent the user from resizing a form vertically, but let them

resize it horizontally (like the Delphi main control form with all the buttons

and the menu on it). How do you do this?

Answer


A:

Well, one way to do this is to trap the WM_NCHITTEST and if it returns

HTBOTTOM, HTBOTTOMLEFT,  HTBOTTOM, HTTOP, HTOPLEFT or HTTOPRIGHT right then

eat it.  This will make windows completely ignore the Window resize if the

mouse is anywhere on the lower or upper border of the Window.  In fact,

windows will not even show the resizing border. Look up this message in the

Windows API.



A:

You can intercept the message (See Message keyword in help) WM_GETMINMAXINFO. It

comes with a structure TMINMAXINFO. You can insert your own values in that

structure

and so limit the position or size that the user is changing.



Check the online help for more information.


Creating a form with a width < 102

Question


Does anybody know how to stop Delphi from resetting a form's width to 102

pixels whenever you set the width to anything less than that?

Answer


A:

Add this definition to intarface section of your form,

  procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);

            message WM_GETMINMAXINFO;



and add this to implementaion section.

  procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);

  begin

    with message do begin

      MinMaxInfo^.ptMinTrackSize.x := 20;

    end;

  end;



A:

I havn't figured anyway to do it from the IDE but you can do at

run-time with



procedure TForm1.Form1OnCreate(Sender: TObject);

begin

  Width := 50;

end;


Disable ALT-F4

Question


How do I disable ALT-F4 for a form?

Answer


Look at the closequery event of a form - if you return false - unless a

certain value is set, then it will only close when it is closed YOUR way----

otherwise, you could put any important shutdown code in there as well....


Dialog box title

Question


Is there any way to set the title for a dialogbox created with

MessageDlg(). In standard (not using CTL3D.DLL) dialogbox it can be

setted (in API-function).

Answer


A:

The dialog-caption gets set from inside the

CreateMessageDialog inside Dialogs.pas. It does a LoadStr to get

the Warningcaption, Cautioncaption and so on so you have two

choices: Either you modify Dialogs.pas or you change the strings

in the .res file.


Forms / Scaled

Question


We're curious about what the relationship is among Scaled, PixelsPerInch

and dynamically creating forms...

Answer


A:

I think the documentation for "PixelsPerInch" is confusing, because in my

experience, this refers to the size in pixels/inch of the system's FONTS, 

not of the form.



For instance, Delphi's default PixelsPerInch property will typically be 96 

for any forms you create, REGARDLESS OF YOUR SYSTEM'S SCREEN RESOLUTION.  

On my system, this seems to be true whether I'm running at 640x480, 

800x600, 1024x768, etc.



However, when changing your screen's resolution, if you specify "Large 

Fonts" instead of "Small Fonts", Delphi's default PixelPerInch will now 

typically be 120 for any forms you create, again regardless of the 

resolution you're running at.



I think Delphi does this for the following reason:  Delphi needs to know 

both the PixelsPerInch of the form as it was designed and at runtime.  With 

this information, Delphi can determine if the form needs to be scaled in

order for all the text (i.e., fonts) to fit as it was designed.





Example:

-------



- You create a form using "Small Fonts".  You leave the PixelsPerInch

   setting at its default of 96.



- Your user tries to run your app using "Large Fonts".  This setup means

  that all the form's text would now be larger relative to the rest of the

  form, because of the larger font sizes.  The PixelsPerInch property of

  this user's setup would be 120.



If your form's "Scaled" property is set to False, Delphi will not do 

anything to compensate.  Your text will probably be larger than when you 

designed it, and some of it my be clipped because it won't fit.



However, if your form's "Scaled" property is set to True, Delphi will 

automatically scale the form by a factor of 120/96.  This way, the form has 

now "grown" to accomodate the larger fonts.  Everything will look as you

designed it.

 



NOTE:  This scaling will only take place if the user's PixelsPerInch 

property is different from the designer's.  As far as I know, this only 

happens when you choose a different font size when changing your screen's 

resolution.



In my case, my forms NEVER scaled themselves, whether at 800x600, 1024x768, 

etc., because I was always using "Small Fonts".  This really had me going 

for awhile.  My solution was to scale the forms manually, using 

ScaleBy(...).  



I suppose another solution would be to change the form's PixelsPerInch 

property at runtime, when the form is about to be created.  This would 

"trick" Delphi into thinking that the form was designed using a different 

PixelsPerInch, so it would adjust accordingly.  For example, changing a 

form's PixelsPerInch property from 96 to 80 during creation would cause 

Delphi to scale the form by a factor of 96/80.


Set focus while modal dialog is open

Question


I'm trying to create a lookup table for my users that will hang around

during the life of my application.  I've got one sticky problem: if I create

a data entry form and showModal it, then the lookup table can't receive

focus!

Answer


A:

The way I am seeing it, the form with the lookup table should be displayed when

you need it from either the main or data entry form by whatever means, a Lookup

Button etc.



I would envisage something like this:



in fMain.formCreate:

   fLookup := tFLookup.create (self);

   {show code removed from here}



in fMain.btn1Click:

   fEntry := tFentry.create (self);

   fEntry.showModal;



in fMain.LookupButtonClick:

   fLookup.showMODAL;



in fEntry.LookupButtonClick:

   fLookup.showMODAL;



in fLookup.DoneButtonClick:

   fLookup.Hide;


Overriding ESC-key on a Form

Question


I have a form on which a couple of TEdits are placed. Now i would

like to overrule the ESC button. Instead of closing the form, the text

in the active Edit-field should be deleted.

Answer


A:

	 (a) check the TEdit's OnKeyPress event for Key = #27

	 (b) if that fails, set the form's KeyPreview property



(set = make it true, reset means make it false) and then in the form's

OnKeyPress event, check for Key = #27.

If these fail, you could always use the windows message system to check for

all keypresses coming in to your application. I did it for a couple of apps for

some other keys, and it's not that hard.  Write if you want an example.


Destroy a Modal Form on Deactivate

Question


I would like to destroy a Modal Form when the application is de-activated.

I've done some testing and research.  Basically, I would use Application

Deactivate event handler.

How do I simulate letting the Modal Form close peacefully?

For a non-modal form, it's so much less complicated... a hide will do.

Note my "Form1" is declared globally that Application.OnDeactivate can

see it.

Answer


A:

procedure TForm1.AppDeactivate(Sender: TObject);

var

  hw: HWnd;

  CurTask: THandle;

  WndStyle:Longint;

begin

  CurTask:=GetWindowTask(handle);

  hw:=GetWindow(GetDesktopWindow, GW_CHILD);

  while GetWindowTask(hw)<>CurTask do

    hw:=GetWindow(hw, GW_HWNDNEXT);

  while (hw<>handle) and (GetWindowTask(hw)=CurTask) do

  begin

    PostMessage(hw, WM_Close, 0, 0);

    hw:=GetWindow(hw, GW_HWNDNEXT);

  end;

end;


Adding BorderIcons to a form

Question


Does anyone know how to add additional border icons to the caption frame

area of a form?

Answer


I've only ever done this stuff iin C, so I'm not sure about how to do it via

native Delphi code, however:

For Windows v3.1x, you'll need to override the WM_NCPAINT message, and use

the GetSystemMetrics function to determine the size of the buttons etc.,

then after calling the inherited WM_NCPAINT, paint your button.  You'll also

need to override WM_NCMOUSEDOWN etc. so that you can process click messages.

You might be able to get an actual TButton or TSpeedButton up there, but it

might end up being harder.

For the system menu, call GetSystemMenu() to get it's handle.  From there

you can call AddMenuItem to add your own items.  You may need to override

WndProc to handle menu picks etc..  There's probably an easier way to do it

in Delphi though.


Closing a modal form

Question


How do I close a modal form without going through a button event handler?

Answer


I think the problem is that the FormActivate handler is called as part of

the focus change to the new form, so Delphi suppresses any other focus

changes while the handler executes. If you have ever tried buggering

about with focus changes using the Windows API you'll know that

changing the focus while the focus is being changed leads to an infinite

loop within Windows !!!



The solution should be simple. Post a WM_CLOSE message to the form that

you want to close, at the end of the OnActivate handler. This works

because the message is queued by Windows until sometime after the

OnActivate handler has finished executing (and hence the focus change has

ended).



I tried it with a simple program;  one form with a button on it that

activates an About dialog, which closes itself immediately.  Not very

useful I admit, but illustrates the principle.



Unit Form1;



.... (usual rubbish ) ...



implementation



uses

  About;



procedure TForm1.Button1Click(Sender: TObject);

begin

  AboutBox.ShowModal;

end;





Unit About;



.... (usual rubbish ) ...



implementation



uses

  Messages;



procedure TAboutBox.FormActivate(Sender: TObject);

begin

  PostMessage( Handle, WM_CLOSE, 0, 0 );

end;





I hope this helps.  If not, do get back.



A:

The better solution is: Put an invisible button in the modal form,

set the property ModalResult to mrOK, and put this code at the end of

the OnActivate procedure:



postmessage(Button1.Handle, wm_mousedown,0,0);

postmessage(button1.Handle, wm_mouseup,0,0);



So the function returns idOK, and you can check if the cancel button

was pressed.


Event for Form move

Question


Event for Form move?

Answer


It is a windows message, it gets sent to the form when the form is moved.

You would declare a procedure and put it in the protected area of the form

class..



Procedure WMMove(Var Message : TWMMove); message WM_Move;



Procedure TForm1.WMMove(Var Message : TWMMove);

begin

  Label1.Caption := 'X = '+IntToStr(Message.XPos)+', Y = '+IntTOStr(Message.

  YPos);

end;



The event gets called during the move as well. So you might need to check if

the mouse is still down.


Copy the screencontents into a form

Question


how to copy the screencontents into a form?

Answer


A:

 procedure TScrnFrm.GrabScreen;

 var



    DeskTopDC: HDc;

    DeskTopCanvas: TCanvas;

    DeskTopRect: TRect;

    

 begin

    DeskTopDC := GetWindowDC(GetDeskTopWindow);

    DeskTopCanvas := TCanvas.Create;

    DeskTopCanvas.Handle := DeskTopDC;



    DeskTopRect := Rect(0,0,Screen.Width,Screen.Height);



    ScrnForm.Canvas.CopyRect(DeskTopRect,DeskTopCanvas,DeskTopRect);



    ReleaseDC(GetDeskTopWindow,DeskTopDC);

end;



A:

var Image3: TImage;



procedure TSaverForm.CopyScreen;

var

  DeskTopDC: HDc;

  DeskTopCanvas: TCanvas;

  DeskTopRect: TRect;

begin

  Image3 := TImage.Create(SaverForm);

  With Image3 do

  begin

    Height := Screen.Height;

    Width := Screen.Width;

  end;

  Image3.Canvas.copymode := cmSrcCopy;

  DeskTopDC := GetWindowDC(GetDeskTopWindow);

  DeskTopCanvas := TCanvas.Create;

  DeskTopCanvas.Handle := DeskTopDC;

  Image3.Canvas.CopyRect(Image3.Canvas.ClipRect, DeskTopCanvas,

   DeskTopCanvas.ClipRect);

  Image2.Picture.Assign(Image3.Picture);

  {image2 is on the saver-form, align at client}

end;



procedure TSaverForm.FormClose(Sender: TObject; var Action: TCloseAction);

begin

  Image3.Free;

end;



Currently I am also digesting some other replies to my question.



A:

Try the following HAX 244 from the Aug/Sept issue of Visual Developer

magazine.  It works and works well.



{ see text description following END. }

unit Scrncap;



interface

uses WinTypes, WinProcs, Forms, Classes, Graphics;



function CaptureScreenRect( ARect: TRect ): TBitmap;

function CaptureScreen: TBitmap;

function CaptureClientImage( Control: TControl ): TBitmap;

function CaptureControlImage( Control: TControl ): TBitmap;



implementation



{ use this to capture a rectangle on the screen }

function CaptureScreenRect( ARect: TRect ): TBitmap;

var ScreenDC: HDC;

begin

	Result := TBitmap.Create;

  with Result, ARect do

  begin

  	Width := Right - Left;

    Height := Bottom - Top;



  	ScreenDC := GetDC( 0 );

    try

    	BitBlt( Canvas.Handle, 0, 0, Width, Height,

      	ScreenDC, Left, Top, SRCCOPY);

    finally

    	ReleaseDC( 0, ScreenDC );

    end;

  end;

end;



{ use this to capture the entire screen }

function CaptureScreen: TBitmap;

begin

	with Screen do

  	Result := CaptureScreenRect( Rect( 0, 0, Width, Height ));

end;



{ use this to capture just the client area of a form or control...}

function CaptureClientImage( Control: TControl ): TBitmap;

begin

	with Control, Control.ClientOrigin do

  	Result := CaptureScreenRect( Bounds( X, Y, ClientWidth,

    																ClientHeight ));

end;



{ use this to capture an entire form or control  }

function CaptureControlImage( Control: TControl ): TBitmap;

begin

	with Control do

  	if Parent = nil then

    	Result := CaptureScreenRect( Bounds( Left, Top, Width,

      							Height ))

    else

    	with Parent.ClientToScreen( Point( Left, Top )) do

      	Result := CaptureScreenRect( Bounds( X, Y, Width, Height ));

end;



end.



{

From:  Visual Developer, HAX #244, Aug/Sept 1996



Taking Snapshots of the Screen with Delphi



In Delphi, if we want to capture the image of a form's client area, we

can call GetFormlmage. But sometimes we want a snapshot of the entire

form--title bar, frame, and all. Or we want a snapshot of the entire

screen. If we were desperate, we might pop up a message box that says,

"Press Print Screen button NOW!" and then figure out a way to get the

screen's mug off the clipboard.

But we're not that desperate.  Combining Delphi canvases with a few GDI

functions makes capturing the screen in code a snap.

CaptureScreenRect, in Listing 1, demonstrates this. It gets the screen's

device context with GetDC(O), and then it copies a rectangular area from

that DC to a bitmap's canvas. To do the copying, it uses BitBlt. The key to

using BitBlt--or any GDI function--with Delphi is remembering that a canvas'

Handle is the DC that Windows needs.

The remaining screen capture functions in Listing 1 gobble up rectangles

and farm out the real work to CaptureScreenRect. CaptureScreen throws

together a rectangle for the whole screen. CaptureClientImage and

CaptureControlImage throw together rectangles for the client area and for

the entire area of a control, respectively.

These four functions can be used to capture any arbitrary screen area,

as well as the screen images of forms, buttons, memos, combo boxes, and

so on. We just tell the little buggers to say cheese--and free the bitmaps

when we're done.

}


Putting Forms into a stream

Question


I am looking for a way to put a form and all its components (such as

a list box, and its items), into a stream so that I can save it for

latter retrieval.

Answer


Delphi has a great function to do it:

procedure WriteComponentResFile(const FileName: string; Instance: TComponent);



Just fill the file name you want to save in and the component to save



and to read it back:

function ReadComponentResFile(const FileName: string; Instance: TComponent):

TComponent;


Forms - Dragging without clicking the caption bar

Question


How can I make a form move by clicking and dragging in the client area

instead of on the caption bar?

Answer


{





 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 as shown in the sample unit

    below.

 

    TIP: If you want a captioness borderless window similar to a floating

    toolbar, set the Form's Caption to an empty string, disable all of the

    BorderIcons, and set the BorderStyle to bsNone.

}



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

  iinherited;                    { 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.



{ The text representation of the .DFM file is below:



object Form1: TForm1

  Left = 203

  Top = 94

  BorderIcons = []

  BorderStyle = bsNone

  ClientHeight = 273

  ClientWidth = 427

  Font.Color = clWindowText

  Font.Height = -13

  Font.Name = 'System'

  Font.Style = []

  PixelsPerInch = 96

  TextHeight = 16

  object Button1: TButton

    Left = 160

    Top = 104

    Width = 89

    Height = 33

    Caption = 'Close'

    TabOrder = 0

    OnClick = Button1Click

  end



end



}




Making apps show minimized

Question


When I select the "Run Minimized" option in Program Manager

to attempt to make my Delphi application execute in a minimized 

state, the Delphi application seems to ignore the setting and 

run normally.  Why is this, and how to I fix it?

Answer


A: Delphi's Application object creates a hidden "application 

   window," and it is that window, rather than your main form, 

   that is being sent the command to show minimized. To fix this, 

   just enter this line of code in your main form's OnCreate event handler:



     ShowWindow(Handle, cmdShow);




Transparent window

Question


How to make windows transparent?

Answer


To create a transparent window, put 'Brush.Style:=bsClear;' in the OnCreate 

event for the form.




Controlling form maximization

Question


How to control form maximization?

Answer


I just wrote out a simple little program that will allow you to control the size 

of a form when it is maximized.  It does this in such a way as to remove the 

flickering that you see if you've been adjusting the size via the resize event.  

Basically, this code traps the wm_getminmaxinfo message. To use this style form 

instead of the Delphi standard, simply compile the following text pascal file 

into a DCU. Then replace occurences of TForm with TMaxForm and add (if you

called the pascal file maxform.pas) maxform to your uses clause.  Here now is 

the short program:



unit Maxform;



interface



uses

  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

  Forms, Dialogs;



type

  TMaxForm = class(TForm)

  private

    { Private declarations }

    fmh, fmw, fml, fmt : word;

    procedure mymax(var m: TWMGETMINMAXINFO);

              message wm_getminmaxinfo;

  published

    property maxheight : word read mh write mh;

    property maxwidth  : word read mw write mw;

    property maxleft   : word read ml write ml;

    property maxtop    : word read mt write mt;

    constructor create(AOwner : TComponent); override;

  end;



implementation



procedure TMaxForm.mymax(var m : TWMGETMINMAXINFO);

begin

  m.minmaxinfo^.ptmaxsize.x := fmw;

  m.minmaxinfo^.ptmaxsize.y := fmh;

  m.minmaxinfo^.ptmaxposition.x := fml;

  m.minmaxinfo^.ptmaxposition.y := fmt;

end;



constructor TMaxForm.create(Aowner : TComponent);

begin

  fmw := screen.width;

  fmh := screen.height;

  fmt := 0;

  fml := 0;

  inherited create(aowner);

end;



end.




Making a form selectable without the main form

Question


How do I make it so that only the form I select comes to 

the top?  (i.e. without the main form)

Answer


Try this in any secondary window that you DON'T want 

dragging the program along:



  ...

  private {This goes in the for's type declaration.}

    { Private declarations }

    procedure CreateParams(VAR Params: TCreateParams); override;

  ...



procedure TForm2.CreateParams(VAR Params: TCreateParams);

begin

  Inherited CreateParams(Params);

  Params.WndParent := GetDesktopWindow;

end;



       By setting the form's parent window handle to the 

desktop, you remove the link that would normally force the 

whole application to come to the top when this form comes to 

the top.



DISCLAIMER: You have the right to use this technical information

subject to the terms of the No-Nonsense License Statement that

you received with the Borland product to which this information

pertains.




Scrolling forms with PgUp and PgDn

Question


How can you do scrolling functions in a TForm component 

using  keyboard commands?  For example, scrolling up and down 

when a  PgUp or PgDown is pressed.  Is there some simple way to 

do this or does it have to be programmed by capturing the 

keystrokes and manually responding to them?

Answer


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;





DISCLAIMER: You have the right to use this technical information

subject to the terms of the No-Nonsense License Statement that

you received with the Borland product to which this information

pertains.




Creating own hotkeys

Question


How can I trap for my own hotkeys?

Answer


First: set the form's KeyPreview := true;



Then, you do something like this:



procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;

  Shift: TShiftState);

begin

  if (ssCtrl in Shift) and (chr(Key) in ['A', 'a']) then

    ShowMessage('Ctrl-A');

end;



DISCLAIMER: You have the right to use this technical information

subject to the terms of the No-Nonsense License Statement that

you received with the Borland product to which this information

pertains.




Hiding a form's title bar

Question


How to hide a form's title bar?

Answer


{ You must USE Winprocs & WinTypes for this to work }



Procedure TYourFormName.HideTitlebar;

Var

  Save : LongInt;

Begin

  If BorderStyle=bsNone then Exit;

  Save:=GetWindowLong(Handle,gwl_Style);

  If (Save and ws_Caption)=ws_Caption then Begin

    Case BorderStyle of

      bsSingle,

      bsSizeable : SetWindowLong(Handle,gwl_Style,Save and

        (Not(ws_Caption)) or ws_border);

      bsDialog : SetWindowLong(Handle,gwl_Style,Save and

        (Not(ws_Caption)) or ds_modalframe or ws_dlgframe);

    End;

    Height:=Height-getSystemMetrics(sm_cyCaption);

    Refresh;

  End;

end;



Procedure TYourFormName.ShowTitlebar;

Var

  Save : LongInt;

begin

  If BorderStyle=bsNone then Exit;

  Save:=GetWindowLong(Handle,gwl_Style);

  If (Save and ws_Caption)<>ws_Caption then Begin

    Case BorderStyle of

      bsSingle,

      bsSizeable : SetWindowLong(Handle,gwl_Style,Save or ws_Caption or

        ws_border);

      bsDialog : SetWindowLong(Handle,gwl_Style,Save or ws_Caption or

        ds_modalframe or ws_dlgframe);

    End;

    Height:=Height+getSystemMetrics(sm_cyCaption);

    Refresh;

  End;

end;






Using an alternate main form

Question


Can I use an alternate main form?

Answer


The following logic allows you to check command-line parameters for a 

certain condition, and determines which of two forms to make the main form:



var

    bCondition: Boolean;

 

 {$R *.RES}



 begin



   bCondition :=  ( ParamStr(1) = 'Form2'); {or whatever trigger condition }



   if bCondition then begin {<<<}

      Application.CreateForm(TForm1, Form1);

   end {<<<} else

      Application.CreateForm(TForm2, Form2);

   Application.Run;



begin...end {<<<} is imperative to let you use the Project Options Dialog.



This tip is adapted from the excellent book 'Delphi Programming Problem

Solver' by Neil Rubenking 1-56884-795-5.




Close    To Top
  • Prev Article-Programming:
  • Next Article-Programming:
  • Now: Tutorial for Web and Software Design > Programming > delphi > Programming Content
    Photoshop Tutorial
     

    Special Effect

      3D Effect
      Photoshop Articles
    Programming Tutorial
     

    C/C++ Tutorial

      Visual Basic
      C# Tutorial
    Database Tutorial
     

    MySQL Tutorial

      MS SQL Tutorial
      Oracle Tutorial
    Geek Tutorial
     

    Blogging Tutorial

      RSS Tutorial
      Podcasting Tutorial
    Graphic Design Tutorial
      Coreldraw Tutorial
      Illustrator Tutorial
      3D Tutorials
    Webmaster Articles
     

    Domain Service

      Web Hosting
      Site Promotion
    Java Tutorial/ Articles
     

    Java Servlets

      JavaEE Tutorial
     

    JavaBeans Tutorial

    XML Tutorial/ Articles
     

    XML Style

      AJAX Tutorial
      XML Mobile
    Flash Tutorial/ Articles
     

    Flash Video

      Action Script
      Flash Articles
    OS Tutorial/ Articles
      Linux Tutorial
      Symbian Tutorial
      MacOS Tutorial
    Personal Tech
      Hardware Tutorial
      Software Tutorial
      Online Auction