This unit contains definition of XForm, representing applet window,
and XControl, which is a base class for all visual controls, placing onto XForm. As You
seen in XApplets unit, where detailed
explanation of creating new XCL project is made, XForm allow to start programming from
about 30 Kbytes of executable (whereas in VCL we started from about 276 Kbytes in D4 and
from about 176 Kbytes in D3). I remind You of why it is so. XForm is not derived from
TPersistent and it has no abilities to read its initial state from executable. Moreovere,
it does not include any capability what is not necessary and can be not used in final
applet. Such additional capabilities are implementing as additional modules
(XFormAutoSize, XAligner and so on) or sometimes by deriving new class from XForm and
overriding its methods (XMDIForm, XMDIChild).
XForm itself is a descender of XWindow
and mainly adds to it capability of handling some additional messages (WM_PAINT, WM_ERASE,
WM_SIZE - overriden) and generate some events (or just stores its to make possible to
generate its in add-on modules).
Here You can read all about XForm class, defined in XForms.pas unit.
And using this reference, You can look at XControl definition
(I decided to separate these two documents because every of each is very important).
XForm = class( XWindow );
XForm properties:
- represents current focused control. Even if control is not windowed, it
therefore can be "focused" in XCL if its CanFocus function returns True. In that
case it receives key input and can change its appearance if this is provided in its
PaintTo method. To move focus to another control of form, either assign True to control's property Focused, or assign it to CurrentControl property of its parent form. If form looses focus, property CurrentControl is not changing. It is possible also assign nil to CurrentControl (saying that there is no focused control in form now). |
- space between client edge and controls, and for controls with children also
space between client edge and children controls. Default is 4. This value is used by
add-on modules (XAligner, XFormAutoSizer, XControlAutoPlacer classes) while executing to
perform its tasks. I would like mark here that XForm can not be scaled or scrolled as TForm in VCL. Therefore, with such add-on modules XForm can look even better than TForm, independantly of screen resolution, set of installed fonts and other factors, which usually confuse Delphi. |
- Default is True. If False, XFormAutoSizer object is not called. You may set
AutoSize to False after placing all controls on form and showing it to prevent further
autosizing when appearance of some elements (labels, buttons and so on) is changing. Anyway, autosizing is performing only in case when You use XFormAutoSizer object (by calling UseFormAutosize). |
Properties, inherited from XWindow:
- it is set when window is created and handle is allocated. Use it to pass it to Windows API functions, requiring window handle (e.g. ShowWindow). |
- returns handle of parent window. If this object is XForm, parent window is an applet button window. For windowed controls, parent window is a form of type XForm and its descenders. For MDI child form, parent window is its MDI parent window. |
- window class style. Default is CS_OWNDC + CS_HREDRAW +
CS_VREDRAW. Look at WNDCLASS topic in Win32.hlp to get more info about other
possible flags. Set it before creating a window (just after constructing the object). It is possible to change class style at any time after creating but it is necessary to repaint the window in that case (e.g. invalidating it) to apply changes. |
- window style. Default is WS_VISIBLE + WS_CLIPCHILDREN
+ WS_CLIPSIBLINGS + WS_CAPTION + WS_SYSMENU + WS_MINIMIZEBOX + WS_MAXIMIZEBOX +
WS_OVERLAPPEDWINDOW. Look at CreateWindow topic in Win32.hlp to get more info
about window styles. Set Style property before creating a window. It is also possible to change style at any time after creating the window. |
- extended window style. Default is 0. Other possible flags are WS_EX_ACCEPTFILES, WS_EX_APPWINDOW,
and more. Look at CreateWindowEx topic in Win32.hlp to get more info about extended window
style flags. Set ExStyle property before creating a window. And it is possible to change style later. |
- default cursor for window class. |
- default icon for window class. |
- default menu for window. |
- caption of window. |
- background color of client area not overlapped by children. This property inherited from XVisual and made public in XWindow. |
- possible states are: wsNormal, wsMinimized, wsMaximized. Default is wsNormal. |
- this property is a type of pointer. It can point to a canvas of type XCanvas but
only in case when canvases module is included into executable (unit XCanvases.pas is used
at least in one of linked modules). To know how it works, look at the XCanvas type
definition. If applet is using canvases, canvas of window can be obtained by calling function WindowCanvas( Window : XWindow ) : XCanvas. |
Properties inherited from XVisual:
- Default is True. Set it to False to disable focusing (and keyboard input) and all mouse events for this object and its children. |
- Default is True. Set it to False to void painting of object (form, control) and taking its rectangle into account while autoplacing of aligned controls. |
- Use it to change position and size of visual object by the single operation to avoid flicks (instead of consequence assignments of values to follow Left, Top, Width and Height properties). |
- Use it to change position of visual object with a single operation instead assigning values to Left and Top properties to reduce resize and realign operations and to avoid flicks. |
Properties inherited from XClass:
XForm methods:
- redirects searching of control at the given position to inherited function
ElementAtPos( X, Y, IgnoreDisabled ) : XVisual. But ControlAtPos is returning nil, if
position is overlapped by visual element which is not an XControl descendant. This function is using mainly in add-on unit XMouseEvents.pas to redirect mouse events to controls of XForm. And You may also use this function for your own purposes. |
- redirects operation to event handler OnGotoControl of GlobalFormsManager object. This event is assigned only if add-on unit XKeyboard.pas is used, to calculate control which has to receive focus after pressing some keys (Tab, Shift-Tab, Right, Left, Up, Down, PgUp, PgDn, Home, End). |
- redirects operation to event handler On_GetAvailableClientRect of GlobalFormsManager object if this event is assigned. If not, it returns the total ClientRect. This function is used usually to align control 'alClient' while realigning, so this event is handled by add-on unit XAligns.pas if it is used in your applet. |
Methods, inherited from XWindow:
- this method is called automatically when its property Handle is required first
time. It forces creation of parent window before creating its own window. When window is
creating, new window class with name 'X' + Int2Str( n ) (where n=1,2,...) is registering
and ClsStyle property is used as style of this class window.
Also properties Color, Cursor, Icon, Menu are using for creating new
class. Newly created class is used to create window handle, and properties Style, ExStyle, Caption are using for calling of CreateWindowEx. Usually You do not need call CreateWindow procedure manually. |
- makes window visible and brings it to front of view (making it active). |
- makes window invisible. |
- transforms coordinates of point given respectively to topleft corner of client area of window to coordinates in screen. |
- handles Windows messages (WM_CLOSE, WM_NCDESTROY, WM_SIZE, WM_SHOWWINDOW,
WM_SYSCOMMAND.SC_MINIMIZE, WM_SETFOCUS, WM_SETCURSOR are handled only. To handle other
messages, override this function and supply code to implement its). This method made public to simplify calling of it from XApplets.pas unit. Usually You do not need call it directly, excluding calling of inherited one in descending class. |
- this method is intended to make process of creating MFC-based controls (which
are using XWindow class) more similar to this one in VCL. It is created from CreateWindow
method to fill Params with some values. Override it to make changes in Params fields
before further processing. For example, You may want to call CreateSubclass before
returning (this will rewrite some fields of Params with values, sensible for appropriate
Windows control, eg. 'STATIC', 'BUTTON', etc.) You usually do not need override this method in XForm descendents. |
- subclasses window with certain standard Windows control data ('STATIC',
'BUTTON', etc.). Must be used in overriden CreateParams method. This method usually is not used in XForm descendents. |
- overrides method inherited from XVisual and returns Handle. This method used internally to handle messages and usually You do not need to call XVisuals.GetWindowHandle( ... ) to obtain window handle. |
- overrides correspondent method of XVisual, returning True. |
Methods, inherited from XVisual:
- This method is leaving as abstract to prevent creating of instances of XVisual
class. Descenders of XVisual (XWindow and XControl)
are implementing this method by the way inherent in each of these two. ClientRect usually is less or equal to BoundsRect in size (but it is always is originating from topleft corner of the client area of visual object itself, so Left and Top are 0 and Right and Bottom are equal to ClientWidth and ClientHeight accordingly). If You want to get ClientWidth and ClientHeight, first call ClientRect once to obtain client rectangle and then use Right and Bottom of that rectangle as ClientWidth and ClientHeight. This is more efficient then calling ClientRect twice (or more) and using ClientRect.Right and ClientRect.Bottom . |
- Searches visual child element taking place at the given position. Only Visible childs are taking into consideration, and if IgnoreDisabled parameter is set to True, then only Enabled childs can be found. If two or more childs are overlapped, then first found is last created. |
- This method is intended in XVisual to return bounding rectangle from topleft
corner of client area of parent window (usually XForm). For XWindow, this function returns ClientRect with topleft corner in (0,0) point. |
- this function is overridden to return actual window bounds rectangle if window is existing. |
- similar function above, this method is overridden to change actual bounding rectangle of window. |
- Invalidates window. |
Following several virtual functions and procedures just inherited but not overridden. |
- This is very important procedure. It must paint visual element (form, control)
onto given device context into given rectangle. XVisual implement just calls PaintChilds
and then PaintErase. If some painting need to be done between these two calls, override
DoPaint and do not call inherited one. Take in attention, that XCustomControl overrides DoPaint, first calling PaintChilds and then PaintTo virtual method, so descending self-painting (not windowed) controls have to use PaintTo to perform painting. |
- Paints childs of visual element. It has to be called before other painting of
visual control itself, because painting of each child is finishing with excluding its area
from clipping area (so it becomes unavailable for further drawing). Such method of painting allows to prevent flickering in most cases (if message WM_ERASEBKGND is ignoring - and it is made so in XCL). The main requirement for self-painting controls is: avoid setting of the pixel more then ones during single paint operation. And all area, what did not fill during painting must be filled with background color AFTER painting. |
- Erases the rest of (non-clipped) Rect area after painting the control and excludes Rect from clipping region calling ExcludeUpdRect. |
- Returns handle of updating region for device context, which was obtained (by XForm) when WM_PAINT message was come in. Virtual method of XVisual returns 0, and it is overriding in XForm and XControl. |
- Excludes rectangle from clip area of given device context. Use this procedure instead of calling API function ExcludeClipRect, because overridden method of XControl and XForm additionally excludes Rect from FUpdRgn:HRgn member, allowing to avoid repainting of other controls not overlapping clipping area (anyway its will not be painted because of clipping but simultaneous deleting excluded Rects from FUpdRgn speeds up executing). |
- Similar ExcludeUpdRect above. Use it instead of ExtSelectClipRgn because it does not only call this API, but also excludes Rgn from FUpdRgn to reduce further painting. |
Methods inherited from XClass:
- use it to create new XClass instance and to assign AParent to it as parent XClass object (this will call method AddChild for AParent to add newly created XClass instance as a child - if AParent is not nil) |
- destructor first calls DeleteChild method for parent XClass object. |
- usually You do not need call AddChild manually. When child created with AParent parameter, procedure AddChild is called automatically for parent to add newly created object as a child of it. |
- also do not call it usually. It is called for parent when child is destroying. |
Events of XForm object:
- these events above are only stored here. Mouse events are handled only
in case when unit XMouseEvents.pas is used (by calling UseStdMouse). And then global
object FormsStdMouseEvents is attaching to On_FormMessage event of GlobalFormsManager and
handling mouse events, redirects it to controls of form or calls form's itself mouse
events OnMouseMove, OnMouseDown, OnMouseUp. Similarly that, keyboard events are handled only when unit XKeyboardEvents.pas is used (by call UseKeyboard). And in that case global object FormsStdKeyEvents is attaching to On_MouseMessage event of GlobalFormsManager and handling keyboard events. It supports passing key messages to "focused" control (if focusing is emulated) or if there are no focused controls or key was not accepted, tabulating between controls with keys Tab,Shift+Tab, arrow keys etc. To make possible attaching more than one handler to the same event On_FormMessage, the technique of joining by chains is applied (saving old handler when joining and calling it if event was not handled by given handler). |
Event, iherited from XWindow object:
XEventAccept = procedure( Sender : TObject; var Accept : Boolean
); - use this event to decide if window can be closed in response to Windows message WM_CLOSE. If not, set Accept to False before return. |
Other definitions of XForms.pas unit:
This class is very important itself and a separate article is devoted to it. It is placed in the same unit with XForm declaration only to make possible its more close interaction (as You know, classes of the same unit have full access to all, even private, fields of each other). |
Also interface class XFormsManager is declared here and single variable GlobalFormsManager of this type. This is derived from TObject and has no methods and properties, but has events:
- stores event handler to make possible drawing of focus rect for focusable self-painting controls using XFocusDrawing.pas add-on unit. Called by control, which needs in focus rectangle, received by handler, installed by FocusPainter global object if this last is used (by calling UseFocusPainter). |
- stores event handler to make possible interception of all messages recived by XForm before its achive the recipient. This event MUST be assigned by chains (i.e. previous handler must be saved in a variable and recalled through if message was not handled). Called by XForm, and used in many other modules (e.g. in add-ons XMouseEvents.pas and XKeyboardEvents.pas). |
- stores event handler to make possible tabulating between controls using
keyboard. If add-on XKeyboardEvents.pas is used (by callig UseStdKeyboard procedure),
following keys are available: (Home, End, Right=Down=PageDown=Tab,
Lef=Up=PageUp=Shift+Tab). This event is called by XForm.GotoControl(VirtKey) procedure, which does nothing itself. |
- stores event handler to make possible autosizing forms and controls. Called by XForm, can receive and handle by global object FormAutosizer (if it is used by call UseFormAutosizer ). |
- stores event handler to make possible calculating of rest of client rect after all left-right and top-bottom aligns (to align alClient-aligned control). Called in function XForm.GetAvailableClientRect, received and handled by global object Aligner (if it is used by calling UseAligner). |
- as above, stores event handler to make possible realigning of controls (which
Align property is not alNone), when form is resizing. Called by XForm in WndProc on
message WM_SIZE, and received and handled by global object Aligner. Even if You use Align for some objects, but do not use alClient alignment, and do not use FormAutoSizer, You may try not to use Aligner. |
It is possible to use XForm object directly, without deriving new
class for form. But I think that it is a good tradition to do so like in Delphi VCL.
Declare controls which You need on form as internal fields of your class derived from
XForm, and override constructor, placing there constructing operators of all children
controls (take in attention, that creation order of controls is also the tab order, so
create focusable controls in the same order as tab order).
Overriding of WndProc procedure is the best way to handle additional
messages, not handled by XForm (and its ancestor XWindow), or to override some of its. (In
XCL You must not use procedures with 'message;'
directive to handle messages).
There are no properties such as FormStyle similar those in VCL TForm.
Instead, to change appearance of form's frame and caption, use Style, ExStyle and ClsStyle
properties. For example, to remove minimize and maximize boxes from caption of form,
write:
with MyForm do Style := Style and not(WS_MINIMIZEBOX or WS_MAXIMIZEBOX); |
Or, to disable close box in caption, write:
with MyForm do ClsStyle := ClsStyle or CS_NOCLOSE; |
To prevent resizing of window by mouse, reset flag WS_THICKFRAME of Style property:
with MyForm do Style := Style and not WS_THICKFRAME; |
Also remember, that first created form becomes "main" window of applet. Minimizing of main window is equal to minimizing the applet, and when main window is closed, applet is fininshing.
When You are designing form, You create and place controls on it. In
Delphi VCL this process is visual, i.e. You drop controls from components palette onto
form, adjust its place and other attributes. This is very convenient, but Delphi uses
technique of storing all data needed by controls in executable in special format, and your
application is necessarily providing with code which will read and interprete such data at
run-time. And this code is not small but very-very big.
In XCL vs VCL we can not design forms visually. We have to write manually
code for creating and adjusting controls atrun-time. I suppose that the best place for
this is in constructor of your form, derived from XForm. It is better to declare form's
controls as private fields of XForm descendent like in VCL.
Yes, this way is not too convenient. But remember, that in charge of it You
obtain very small executable. At least, if You sufficiently creative, it is possible to
design certain external tool application, which could be play role of design-time forms
creation environment and help to design forms visually. Such tool could give controls
definition from special text file in certain format or even from specially formatted
comments in source. (If anybody is interested in performing this task, e-mail me to discuss it).
And in table below You can see list of some of available add-ons, which can be used to include (or not used to exclude) some additional capabilities, not included into XForm itself. Remember, that to use add-on, it is not sufficient to refer onto it in uses clouse. It is necessary also make call of special initialization procedure (right column of table). The best place to do it is dpr-file. Make all such calls before creating of first form (or even before creating the Applet) - in any order You wish.
Global variable |
unit |
initialization call |
---|---|---|
Aligner | in XAligner.pas | UseAligner |
- add-on to apply aligning of controls, which Align property is not
equal to alNone. If not added, Align property is ignored.
|
||
FormAutoSizer | in XFormAutoSize.pas | UseAutoSizer |
- add-on to autosize form and its children controls having children to
fit all embedded children controls when its size is changing. Very convenient and not too
cost add-on, which allow forms to look better independently of screen resolution, fonts
installed and so on. Even more useful in cumulate with ControlAutoPlacer
add-on (see below).
|
||
FormsStdKeyEvents | in XKeyboardEvents.pas | UseKeyboard |
- add-on to handle keyboard events by self-painted (non-windowed). If
not added, keyboard is ignored (excluding system keys, handling by default). If included,
also allow tabulate between focusable controls on form. If You are using only windowed controls, You do not need to use this add-on to handle keyboard when such controls are intended to work with keyboard (some kinds of edit controls).
|
||
FormsStdMouseEvents | in XMouseEvents.pas | UseStdMouse |
- add-on to handle mouse events. If not added, mouse events are
ignored by XForm and not passed to self-painting controls derived from XCustomControl. If You are using only windowed controls, You do not need to use this add-on, and such controls receives mouse messages directly.
|
||
ControlAutoPlacer | in XControlAutoPlace.pas | UseControlAutoPlacer |
- add-on to autoplace controls to avoid overlapping of them. If added,
uses Margin property to make space between controls and spacepads from
client rectangle edge (of form or control); ControlAutoPlacer usually places every new control below from bottom available one. To start placing certain control in top of next column, assign some value to its Left property, or call Place method of control (see XControl definition). Or make it a child of certaing control, which is placed so (XPanel, XBevel, XGroup). Property VerticalOnly can be set to True, if You prefer to use other ways to place controls in several columns (method Place, or XSplitPanel as columns separator).
|
||
ResizeAntiFlicker | in XResize.pas | UseResizeAntiFlicker |
- add-on to eliminate flickering of opposite-aligned controls during
resize of x-form with mouse. Thus is, when this add-on is used, it prevents the most of
such flicks, so XCL form become really stable and looking good. There was additional property FixResize added to XControl definition. By default it is False. Make it True (when ResizeAntiFlicker is used) to skip control area from auto-scrolling. Usually it is not need to proper working of the add-on but sometimes this one can be useful. E.g., this property was used to fix scrollbars of XScrollBox and to fix drop button (which is centering its drop arrow, but this is contradictory to standard scroll strategy and could lead to additional flicks). I also recommend to set this property to True for controls, which are centering its content (text, image). |