Delphi And RTTI… Moving Controls At Runtime
by gdenyer on Sep.18, 2013, under giLE2D Dev
Developing giLE2D in Delphi 2010 has been GREAT FUN! I’ve been using Delphi since version 1 (1995).
I wanted to produce a map editor that would not rely on any expensive hardware acceleration, but still have good performance. Here enters TWinControl and its decendants, with the help of GDIPCustomItem…!
While in most situations you arrange all the controls on a Delphi form in a “fixed” position, there are situations when you need to allow a user to change the placement and dimension of controls at run-time.
This is the foundation of the editor… using run time type information (RTTI) to get the job done.
I played around with trying to use a TPanel with a child TImage control to represent sprites, but I just didn’t have the time to incorporate the flexibility I needed for such an object. I am, though, a proud licensee of the fabulous TMS Component library for Delphi. One of their controls gave me exactly what I needed to represent sprites.
The control, TAdvGlowButton, is a descendant of TWinControl (essential here, because I need a window handle HWND for reference). It comes with excess baggage, but I can strip this baggage using RTTI and inherit from it to implement my own interface to the object. It has an implementation of an interface to handle GDI image types, such as TGA and of course, the ubiquitous PNG, so painting and re-drawing the object, not to mention its support for embedded images, made it a no-brainer. The only concern was the GDI handle count under an OS like WinXP (which I do not intend to fully support anyway).
For example, I strip all of its MouseDown, MouseMove and MouseUp events and implement my own at runtime. That way, the end-user can drag and place the control anywhere on the map surface.
You end up getting a nice class implementation:
type TMethodArray = array of TMethod;
TMover = class(TComponent)
...
...
...
private
OnClickMethods : TMethodArray;
MouseDownMethods : TMethodArray;
MouseMoveMethods : TMethodArray;
MouseUpMethods : TMethodArray;
KeyDownMethods : TMethodArray;
All these event methods can be juxtaposed at my own whim (making the control either static or moveable).
For example, in the RTTI mousemove replacement:
procedure TMover.ControlMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
const
minWidth = 20;
minHeight = 20;
var
newPos: TPoint;
begin
if inReposition then
begin
with TSpriteBlock(Sender) do // TWinControl
begin
GetCursorPos(newPos);
Screen.Cursor := crSize;
Left := Left - oldPos.X + newPos.X;
Top := Top - oldPos.Y + newPos.Y;
oldPos := newPos;
// pass all sprite properties
PopulateProperties(TSpriteBlock(Sender), fmMain.Inspector);
end;
pbGrid.Update; //Repaint;
PositionNodes(TWinControl(Sender));
NeedSave := True;
end;
end;
Totally Delphi, totally not much code and TOTALLY re-useable!! Delphi really kicks ass… it amazes me still!
As you may have guessed, TSpriteBlock is the inherited class from TAdvGlowButton! Great!
Anyway, hope this insight has been interesting to geeks and non-geeks alike!