I.T. Discussion Community!
-Collapse +Expand
Delphi
Search Delphi Group:

Advanced
-Collapse +Expand Delphi To/From
To/FromCODEGuides
-Collapse +Expand Delphi Store
PRESTWOODSTORE

Prestwood eMagazine

January Edition
Subscribe now! It's Free!
Enter your email:

   ► KBProgrammingDelphi for W...Using Controls   Print This     
 
Delphi Using Controls:
Components 101: Form Size Limiting
 
Posted 12 years ago on 12/12/2008 and updated 2/23/2009
Take Away:

Windows sends the WM_GETMINMAXINFO message when the user tries to resize a window either by clicking the maximize button or dragging the borders of the window. By creating a suitable message-response method, you can specify the minimum and maximum window sizes for that form.

KB101672

From the Prestwood Delphi Gazette: Nov 1998 Issue

Windows sends the WM_GETMINMAXINFO message when the user tries to resize a window either by clicking the maximize button or dragging the borders of the window. By creating a suitable message-response method, you can specify the minimum and maximum window sizes for that form.

If you want to limit a form's size using this technique, however, you'll need to make the modifications we suggested to each form's source code. Granted, you can simply copy and paste the source code from one project to the next, but it can be annoying to repeat this task for each size-limited form. As an alternative, you could create a form template, but you may find that you want to limit the size of forms you create from other templates.

In this article, we'll show you how to create the FormSizeLimit component, which encapsulates the work of responding to the WM_GETMINMAXINFO message. In addition, this component makes it easy for you to adjust the form's size limits dynamically, simply by changing the component's appropriate properties.

Messing with form messages
To respond directly in a form to the message WM_GETMINMAXINFO, you must create a new method that responds to this Windows message. Delphi simplifies this assignment by mapping all the standard messages. All you have to do is to add the message keyword and the corresponding message identifier to the end of a form-procedure method. Delphi will automatically call the new method when the form receives the WM_GETMINMAXINFO message. Unfortunately, it's not so simple to capture this message from a component on a form. After all, Windows won't send the WM_GETMINMAXINFO message to a component, since it's not trying to resize the component.

The secret to capturing this message from a component lies in providing a new window procedure for the form that will respond to the appropriate messages, and pass all others on to the form's original window procedure. If the user removes the component that provides the new window procedure, you'll need to make sure you reinstall the old window procedure.

Specifically, we'll want our component to respond to two messages that Windows will send to the enclosing form: WM_SIZE and WM_GETMINMAXINFO. We'll respond to the WM_SIZE message to add some handy design-time capabilities, and we'll respond to the WM_GETMINMAXINFO message to perform the runtime size-limiting function.

Sizing up FormSizeLimit
To use the FormSizeLimit component, simply add it to an existing form. When you do, you'll see the properties of the FormSizeLimit component appear in the Object Inspector. Most of the properties for this component are self-explanatory. For example, the FormSizeLimit component will limit the size of the form only when you've set the Active property to True. However, the AutoTrack property requires a bit of explanation. If you set the AutoTrack property to True, the FormSizeLimit component will monitor the changes you make to the size of the form at design-time, and it will adjust the MaxHeight and MaxWidth properties to the design size. If you reduce the size of the form to less than the values specified in the MinHeight and MinWIdth properties, the component will automatically reduce those properties to reflect the new size. This adjustment prevents a situation in which the minimum dimensions are greater than the maximum dimensions. To take advantage of the AutoTrack property, we suggest you use the following steps to set the minimum and maximum sizes:

  • Set the AutoTrack property to True.
  • Set the MinHeight and MinWidth properties to values that are a few pixels smaller than the MaxHeight and MaxWidth properties.
  • Reduce the size of the form to the minimum size you want at runtime.
  • Reset the AutoTrack property to False.

To download the source code, visit the file repository web-site.


unit Frmszlmt;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, 
  Classes;

type
  TMinSizeError     = class(Exception);
  TNotSizeableErro  = class(Exception);
  TNotOwnerError    = class(Exception);
  TDuplicationError = class(Exception);

  TFormSizeLimit = class(TComponent)
  private
    FActive        : Boolean;
    FAutoTrack     : Boolean;
    FAbsMinHeight  : Word;
    FAbsMinWidth   : Word;
    FMaxWidth      : Word;
    FMinWidth      : Word;
    FMaxHeight     : Word;
    FMinHeight     : Word;
    FFormHandle    : Hwnd;
    FWndHandlerPtr : Pointer;
    FOldWndHandler : Pointer;
    FMaxRange      : TPoint;
    FMinRange      : TPoint;

    procedure AdjustMinMaxMessage(MMPointer : 
                                  Pointer);
    procedure ChkMaxHeight(Setting : Word);
    procedure ChkMaxWidth(Setting : Word);
    procedure ChkMinHeight(Setting : Word);
    procedure ChkMinWidth(Setting : Word);
    procedure NWndProc(var Messg: TMessage);
    procedure SetNewSize(NewCLWidth, 
                       NewCLHeight : Word);
  protected
    { Protected declarations }
  public
    constructor Create(AOwner : TComponent); 
                override;
    destructor Destroy; override;

    procedure Loaded; override;
  published
    property Active    : Boolean  
        read FActive write FActive;
    property AutoTrack : Boolean
        read FAutoTrack write FAutoTrack;
    property MaxHeight : Word 
        read FMaxHeight write FMaxHeight;
    property MinHeight : Word 
        read FMinHeight write FMinHeight;
    property MaxWidth  : Word 
        read FMaxWidth write FMaxWidth;
    property MinWidth  : Word 
        read FMinWidth write MinWidth;
  end;

procedure Register;

implementation

uses
  Forms, Controls;

constructor TFormSizeLimit.Create(AOwner : TComponent);
var
  I                  : Word;
  FormSizeLimitCount : Byte;

begin
  FormSizeLimitCount := 0;
  inherited Create(AOwner);

  if (AOwner is TForm) then
  begin
    with (AOwner as TForm) do
    begin
      if csDesigning in ComponentState then
      begin
        for i := 0 to ComponentCount - 1 do
          if Components[i] is TFormSizeLimit 
            then inc(FormSizeLimitCount);

        if FormSizeLimitCount > 1 then
          raise TDuplicationError.Create(
                 'Already a FormSizeLimit ' +
                 'component on selected  ' +
                 'form');
        if BorderStyle <> bsSizeable then
          raise TNotSizeableError.Create(
                 'Form does not have ' +          
                 'BorderStyle of  '+
                 'bsSizeable');

        FMinHeight := 
                  GetSystemMetrics(SM_CYMIN);
        FAbsMinHeight := FMinHeight;
        FMinWidth := 
                  GetSystemMetrics(SM_CXMIN);
        FAbsMinWidth := FMinWidth;
        FMaxHeight := Height;
        FMaxWidth  := Width;
      end;
      FFormHandle := Handle;
      FOldWndHandler := Pointer(
                  GetWindowLong(FFormHandle, 
                  GWL_WNDPROC));
      FWndHandlerPtr := MakeObjectInstance(
                         NWndProc);

      if FWndHandlerPtr = nil then
        raise EOutOfResources.Create(
              'Windows Resources exhausted');
      SetWindowLong(FFormHandle, GWL_WNDPROC, 
                    LongInt(FWndHandlerPtr));
    end;
  end else
    raise TNotOwnerError.Create('A Form ' +
                       'MUST be the owner');
end;

procedure TFormSizeLimit.Loaded;
begin
  inherited Loaded;

  FMaxRange.X := FMaxWidth;
  FMaxRange.Y := FMaxHeight;
  FMinRange.X := FMinWidth;
  FMinRange.Y := FMinHeight;
end;

destructor TFormSizeLimit.Destroy;
begin
  FAutoTrack := False;

  SetWindowLong(FFormHandle, GWL_WNDPROC, 
                LongInt(FOldWndHandler));
  if FWndHandlerPtr <> nil then
    FreeObjectInstance(FWndHandlerPtr);

  inherited Destroy;
end;

procedure TFormSizeLimit.ChkMaxHeight(Setting 
                                     : Word);
begin
  if (csDesigning in ComponentState) and
     (not (csLoading in ComponentState)) then
    if (Setting < MinHeight) then
      raise TMinSizeError.Create('The ' + 
           'Maximum Height must not be' +        
            Chr(13) + 
           'less than the Minimum Height');

  FMaxHeight := Setting;
  FMaxRange.Y := Setting;
end;

procedure TFormSizeLimit.ChkMaxWidth(Setting     
                                    : Word);
begin
  if (csDesigning in ComponentState) and
     (not (csLoading in ComponentState)) then
    if (Setting < MinWidth) then
      raise TMinSizeError.Create('The ' + 
            'Maximum Width must not be' +            
            Chr(13) + 
            'less than the Minimum width');

  FMaxWidth := Setting;
  FMaxRange.X := Setting;
end;

procedure TFormSizeLimit.ChkMinHeight( 
                         Setting: Word);
begin
  if (csDesigning in ComponentState) and
     (not (csLoading in ComponentState)) then
  begin
    if (Setting < FAbsMinHeight) then
      raise TMinSizeError.Create('The ' +
              'Minimum Height must not' +  
               Chr(13) + 
              'be less than the caption  ' +
              'height');
    if (Setting >= FMaxHeight) then
      raise TMinSizeError.Create('The ' +  
           'Minimum Height must not be' + 
            Chr(13) +
           'greater than the Maximum ' +
           'height');
  end;

  FMinHeight := Setting;
  FMinRange.Y := Setting;
end;

procedure TFormSizeLimit.ChkMinWidth(Setting: Word);
begin
  if (csDesigning in ComponentState) and
     (not (csLoading in ComponentState)) then
  begin
    if (Setting < FAbsMinWidth) then
      raise TMinSizeError.Create('The ' +
       'Minimum width must not be less' +       
       Chr(13) + 
       'than the caption controls width');
    if (Setting >= FMaxWidth) then
      raise TMinSizeError.Create('The ' +
            'Minimum width must not be' + 
            Chr(13) + 
            'greater than the Maximum ' +
            'width');
  end;

  FMinWidth := Setting;
  FMinRange.X := Setting;
end;

procedure TFormSizeLimit.SetNewSize(NewCLWidth, 
                         NewCLHeight : Word);
var
  NewWidth  : Word;
  NewHeight : Word;
  SavActive : Boolean; 

begin
  NewWidth := NewCLWidth + 
          (GetSystemMetrics(SM_CXFRAME) * 2);
  NewHeight := NewCLHeight + 
         (GetSystemMetrics(SM_CYFRAME) * 2) + 
         (GetSystemMetrics(SM_CYCAPTION) - 
         (GetSystemMetrics(SM_CYBORDER));

  SavActive := FActive;
  FActive := False;

  if (NewWidth < MinWidth) then
    FMinWidth := NewWidth;

  if (NewHeight < MinHeight) then
    FMinHeight := NewHeight;

  MaxWidth  := NewWidth;
  MaxHeight := NewHeight;
  FActive   := SavActive;
end;

procedure TFormSizeLimit.AdjustMinMaxMessage(
                        MMPointer : Pointer);
var
  MinMaxPtr : ^TMinMaxInfo;

begin
  MinMaxPtr := MMPointer;
  MinMaxPtr^.ptMinTrackSize := FMinRange;
  MinMaxPtr^.ptMaxTrackSize := FMaxRange;
end;

procedure TFormSizeLimit.NWndProc(var Messg: TMessage);
begin
  with Messg do
  begin
    case Msg of
      WM_GETMINMAXINFO : if (FActive and not 
        (csDesigning in ComponentState)) then
        AdjustMinMaxMessage(Pointer(lParam));
      WM_SIZE : if (csDesigning in 
                    ComponentState) and 
                   (FAutoTrack) and
               (wParam = SIZE_RESTORED)) then
          SetNewSize(LoWord(lParam), 
                     HiWord(lParam));
    end;

    result := CallWindowProc(FOldWndHandler, 
              FFormHandle, Msg, wParam, 
              lParam);
  end;
end;

procedure Register;
begin
  RegisterComponents('Additional', 
                     [TFormSizeLimit]);
end;

end.

Comments

0 Comments.
Share a thought or comment...
 
Write a Comment...
...
Sign in...

If you are a member, Sign In. Or, you can Create a Free account now.


Anonymous Post (text-only, no HTML):

Enter your name and security key.

Your Name:
Security key = P1202A1
Enter key:
Article Contributed By Larry J. Rutledge :
I worked for Prestwood Software as a Delphi developer from 1997 through 2002. During that time I enjoyed working with Mike Prestwood and the other developers at Prestwood.
Visit Profile

 KB Article #101672 Counter
9226
Since 12/12/2008

Follow PrestwoodBoards on: 


©1995-2020 PrestwoodBoards  [Security & Privacy]
Professional IT Services: Coding | Websites | Computer Tech