Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying hints

I have added hints to components on my form. When the components receive the focus, I'd like to set the caption of a label component to display the hint.

I have added a TApplicationEvents object and set the OnShowHint event to

procedure TImportFrm.ApplicationEvents1ShowHint(var HintStr: string;
  var CanShow: Boolean; var HintInfo: THintInfo);
begin
  HelpLbl.Caption := HintStr;
end;

However it seems that the ShowHint event only fires with mouse movements. Is there a way to fire the hint code when components receive focus, without having to implement the OnEnter event for every single component on the form?

like image 671
Sam M Avatar asked Dec 06 '11 23:12

Sam M


4 Answers

Add a handler for TScreen.OnActiveControlChange in your main form's creation, and handle the hints in that event:

type
  TForm2=class(TForm)
  ...
  private
    procedure ScreenFocusControlChange(Sender: TObject);
  end;

implementation

procedure TForm2.FormCreate(Sender: TObject);
begin
  Screen.OnActiveControlChange := ScreenFocusControlChange;
end;

procedure TForm2.ScreenFocusControlChange(Sender: TObject);
begin
  Label1.Caption := ActiveControl.Hint;
  Label1.Update;
end;

Note that Sender won't do you much good; it's always Screen. You can filter (for instance, to only change the Label.Caption for edit controls) by testing the ActiveControl:

if (ActiveControl is TEdit) then
  // Update caption of label with ActiveControl.Hint

Note that if you'll need to reassign the event when you show child forms (to an event on that child form), or you'll always be updating the original form's label with the hints. The easiest way to do the reassignment is to give every form an OnActiveControlChange handler, and assign it in the form's OnActivate event and unassign it in the OnDeactivate event:

procedure TForm1.FormActivate(Sender: TObject);
begin
  Screen.OnActiveControlChange := Self.ScreenActiveControlChange;
end;

procedure TForm1.FormDeactivate(Sender: TObject);
begin
  Screen.OnActiveControlChange := nil;
end;

This will allow you to update controls other than Label1 on each form, and only use the hint changes on forms you want to do so.

like image 186
Ken White Avatar answered Oct 15 '22 01:10

Ken White


A simple solution is to use OnIdle event:

procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
  if Assigned(ActiveControl) then
    Label1.Caption:= ActiveControl.Hint;
end;

A more advanced solution is to override protected ActiveChanged method of TForm:

type
  TForm1 = class(TForm)
    ...
  protected
    procedure ActiveChanged; override;
  end;

...

procedure TForm1.ActiveChanged;
begin
  inherited;
  if Assigned(ActiveControl) then
    Label1.Caption:= ActiveControl.Hint;
end;

Receiving focus and OnShowHint are quite different events; OnShowHint can be triggered for non-focused control as well.

like image 22
kludg Avatar answered Oct 14 '22 23:10

kludg


Why would you need to implement the OnEnter event for every single component? You can create one generic method / event handler like:

procedure TForm1.AnyControlEnter(Sender: TObject);
begin
  lbl1.Caption := TControl(Sender).Hint;
end;

and assign it to every component you placed on the form.

like image 1
Pateman Avatar answered Oct 15 '22 01:10

Pateman


You said:

it seems that the ShowHint event only fires with mouse movements

This is a normal behaviour. The problem you have ( it's a guess) is that hints are not fired directly. Don't try to make a workaround, what you try to do with MouseEnter is exactly what is already happening...the only difference is that you'be forget something...

Keep the event ApplicationEvents1ShowHint() as you've initially done but add this in the form constructor event:

Application.HintPause := 1;

And then hints will be displayed (almost) without delay.

like image 1
az01 Avatar answered Oct 15 '22 01:10

az01