Question:
How can I create a form that doesn’t have a caption, but can be re-sized?
Answer:
Many folks would say, “Just set the BorderStyle of the form to bsNone and you’ll remove the caption.” However, there’s a problem with that suggestion: Not only do you lose the caption bar, you lose the entire border, which means you can’t resize the form. The only way to get around this is to go behind the scenes in Delphi. Fortunately, it’s a relatively simple process.
Delphi is not just ObjectPascal; it is also a very effective wrapper of the Windows API (Don’t worry, we won’t get into the Windows API too much in this article). In Windows, every window is created using one of two standard functions: CreateWindow and CreateWindowEx. CreateWindow makes a window with standard window styles, while CreateWindowEx is the same as CreateWindow, but you can add extended window styles to the window you want to create. (I encourage you to read through the help file for a thorough discussion of these two API calls since I won’t be going into detail with these topics.)
When a form is created in Delphi, a call is made to CreateWindowEx ? TForm’s Create method is the wrapper function for this call ? and Create passes a record structure to CreateWindowsEx through a virtual method of TForm called CreateParams.
CreateParams is a virtual method of TForm. This means you can override it which, in turn, means you can change the default style of a window when it’s created to suit your particular needs. For our purposes, we want to eliminate the caption. That’s easily done by changing the style bits of the LongInt Style field of the TCreateParams structure, the record that’s passed to CreateWindowEx. Look at the code; we’ll discuss particulars below:
unit NoCap;interfaceuses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, BDE, DB;type TForm1 = class(TForm) Button1 : TButton; procedure Button1Click(Sender: TObject); private {Here’s what we’re overriding} procedure CreateParams(VAR Params: TCreateParams); override; procedure WMNCHitTest(VAR Msg: TWMNcHitTest); message WM_NCHITTEST; end;var Form1: TForm1;implementation{$R *.DFM}procedure TForm1.CreateParams(VAR Params: TCreateParams);begin Inherited CreateParams(Params); WITH Params DO Style := (Style OR WS_POPUP) AND (NOT WS_DLGFRAME); {or… Style := Style + WS_POPUP – WS_DLGFRAME; which is the equivalent to the above statement} end;procedure TForm1.WMNCHitTest(var msg: TWMNCHitTest);begin inherited; if (msg.Result = htClient) then msg.Result := htCaption;end;procedure TForm1.Button1Click(Sender: TObject);begin Close;end;end.
Notice in the line in CreateParams where I set the Style for the form: Style := (Style OR WS_POPUP) AND (NOT WS_DLGFRAME);
. My first bit manipulation is Style OR WS_POPUP. This means give me the default style bits and make the window a regular pop-up window with a resizeable border. The second portion says don’t include a dialog frame. With respect to this, the WS_DLGFRAME will produce a frame typical of dialog boxes. By masking it out, you remove the title bar. WS_POPUP ensures you have a resizeable border with which to work.
What about the WMNCHitTest message handler? Well, if you have a form with no title bar, you have absolutely no way to move it, because by convention, forms are moved by dragging the title bar. By trapping a mouse hit with the WM_NCHITTEST message and changing the default behavior of the mouse hit, you can allow dragging of the form from the client area.
Read through the Windows API help and look at all the style bits you can set. Play with different combinations to see what you get.