Delphi RSS Resources, Delphi Components, Delphi Sites, Articles, Dynamic XML Feeds, Tutorials, Sources
 
 
 
Google
 
Web delphirss.com
| Server-Scripts.com | Informations for JAVA | Informations for PHP | SEO Web Links | Borland Delphi
 

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.










© DelphiRSS.com. All Rights Reserved.