I have written a component that paints a picture centered at X,Y. At runtime, the component is moved around with a SetXY(X,Y: integer)
procedure.
To acheive this, I calculate what the Left
and Top
values should be in the paint routine and set them accordingly. And all that works just fine.
But when I try to do the initial positioning at design-time, I cannot position the component by dragging it to the desired location.
When I set either the Left
or Top
property via the Object Inspector, it works.
procedure MyCustomComponent.SetTop(const Value: integer);
begin
if Top = (Value) then
exit;
inherited Top := Value;
if csDesigning in ComponentState then
FY := Value + FBmp.Width div 2;
Invalidate;
end;
procedure MyCustomComponent.SetLeft(const Value: integer);
begin
if Left = (Value) then
exit;
inherited Left := Value;
if csDesigning in ComponentState then
FX := Value + FBmp.Width div 2;
Invalidate;
end;
I suspect that when the component is dragged and dropped at design-time on the Form, it does not actually set the Left
and Top
public properties, but instead calls some other function that sets the private field members of the underlying control that I inherit the component from (TGraphicControl
).
As Both fpiette and Remy pointed out, overriding the SetBounds
did the trick. When positioning a component in design time via dragging and dropping the component it does not individually set the public Left
and Top
properties. But instead makes a call to the SetBounds
procedure.
procedure MyComponent.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
inherited;
if csDesigning in ComponentState then begin
FX := ALeft + FBmp.Width div 2;
FY := ATop + FBmp.Height div 2;
end;
end;
After testing i found that for the component to be placed correctly on the form in runtime you have to also check the csLoading
in component state.
So a more complete solution would be like this:
procedure MyComponent.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
inherited;
if (csDesigning in ComponentState) or (csLoading in ComponentState ) then begin
FX := ALeft + FBmp.Width div 2;
FY := ATop + FBmp.Height div 2;
end;
end;