I have a custom TLabel
that in principle can be attached to any other visual component in the form. The component has a property position
which tells where it will be positioned towards the attached control (left, above, etc.). This works fine when the related control is attached, and the component positions itself according to the position
property.
Problem is that I can't make the component detect when the related control changes it bounds so it can properly reposition itself. I guess that has to do with WMMove
and WMResize
. How can I do for the related control to notify the TLabel
that any of the bounds properties has changed?
Binding managers provide a central repository of information for data-bound controls on a Windows Form that are bound to the same data source. In doing so, binding managers enable the synchronization of related controls.
To create a control that is bound to a field (meaning that the control will display and let you edit data from a table), open the Field List (Alt+F8) and drag the field from the list to the form, view, or report. Access adds a control that is appropriate for the type of data stored in the field.
A control's OnResize
event is triggered whenever its position and/or dimension changes. So one simply solution is to assign a handler to that event when you attach your Label to a control, eg:
private
FControl: TControl;
// OnResize is protected in TControl so use an accessor class to reach it...
type
TControlAccess = class(TControl)
end;
procedure TMyLabel.Destroy;
begin
SetControl(nil);
inherited;
end;
procedure TMyLabel.SetControl(AControl: TControl);
begin
if FControl <> AControl then
begin
if FControl <> nil then
begin
TControlAccess(FControl).OnResize := nil;
FControl.RemoveFreeNotification(Self);
end;
FControl := AControl;
if FControl <> nil then
begin
FControl.FreeNotification(Self);
TControlAccess(FControl).OnResize := ControlResized;
end;
...
end;
end;
procedure TMyLabel.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FControl) then
FControl := nil;
end;
procedure TMyLabel.ControlResized(Sender: TObject);
begin
// reposition as needed...
end;
Of course, this will cause issues if the user wants to assign their own OnResize
handler to the control.
The alternative is to subclass the control's WindowProc
property instead:
private
FControl: TControl;
FControlWndProc: TWndMethod;
procedure TMyLabel.Destroy;
begin
SetControl(nil);
inherited;
end;
procedure TMyLabel.SetControl(AControl: TControl);
begin
if FControl <> AControl then
begin
if FControl <> nil then
begin
FControl.WindowProc := FControlWndProc;
FControl.RemoveFreeNotification(Self);
end;
FControl := AControl;
if FControl <> nil then
begin
FControlWndProc := FControl.WindowProc;
FControl.WindowProc := ControlWndProc;
FControl.FreeNotification(Self);
end else
FControlWndProc := nil;
...
end;
end;
procedure TMyLabel.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FControl) then
begin
FControl := nil;
FControlWndProc := nil;
end;
end;
procedure TMyLabel.ControlWndProc(var Message: TMessage);
begin
FControlWndProc(Message);
// now check for position/size messages and reposition as needed...
end;
Based on @RemyLebeau answer and some concept ideas from ExtCtrls.TLabeledEdit
I have wrote my own TStickyLabel
control. (Work in progress). Remy's answer should be accepted of-course :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With