Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
380 views
in Technique[技术] by (71.8m points)

pascalscript - Inno Setup: OnHover event

Is it possible to simulate OnMouseHover event (to call a function when mouse is over some Inno Setup control) for Inno Setup controls, or is there any DLL library which can help?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can implement it by:

  • scheduling a very frequent timer (say 50 ms)
  • when the timer is triggered, find a control over which the cursor is positioned and check for changes.

The following example displays name of the control with cursor over it on a label, like:

enter image description here

[Code]

var
  HoverLabel:TLabel;
  LastMouse: TPoint;
  LastHoverControl: TControl;

function GetCursorPos(var lpPoint: TPoint): BOOL;
  external 'GetCursorPos@user32.dll stdcall';
function SetTimer(hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord):
  LongWord; external 'SetTimer@user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ScreenToClient@user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ClientToScreen@user32.dll stdcall';

function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
  Control: TControl;
  WinControl: TWinControl;
  I: Integer;
  P2: TPoint;
begin
  { Top-most controls are the last. We want to start with those. }
  for I := Parent.ControlCount - 1 downto 0 do
  begin
    Control := Parent.Controls[I];
    if Control.Visible and
       (Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
       (Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
    begin
      if Control is TWinControl then
      begin
        P2 := P;
        ClientToScreen(Parent.Handle, P2);
        WinControl := TWinControl(Control);
        ScreenToClient(WinControl.Handle, P2);
        Result := FindControl(WinControl, P2);
        if Result <> nil then Exit;
      end;

      Result := Control;
      Exit;
    end;
  end;
  
  Result := nil;
end;

procedure HoverControlChanged(Control: TControl);
begin
  if Control = nil then
  begin
    HoverLabel.Caption := 'no control';
  end
    else
  begin
    HoverLabel.Caption := Control.Name;
  end;
end;

procedure HoverTimerProc(
  H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
  P: TPoint;
  Control: TControl; 
begin
  GetCursorPos(P);
  if P <> LastMouse then { just optimization }
  begin
    LastMouse := P;
    ScreenToClient(WizardForm.Handle, P);
    
    if (P.X < 0) or (P.Y < 0) or
       (P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
    begin
      Control := nil;
    end
      else
    begin
      Control := FindControl(WizardForm, P);
    end;
    
    if Control <> LastHoverControl then
    begin
      HoverControlChanged(Control);
      LastHoverControl := Control;
    end;
  end;
end;

procedure InitializeWizard();
begin
  SetTimer(0, 0, 50, CreateCallback(@HoverTimerProc));
 
  HoverLabel := TLabel.Create(WizardForm);
  HoverLabel.Left := ScaleX(8);
  HoverLabel.Top := WizardForm.ClientHeight - ScaleY(32);
  HoverLabel.Parent := WizardForm;
  HoverLabel.Caption := 'starting';
end;

For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library.


An alternative way to implement this without a timer is to handle relevant windows messages in a handler set using GWL_WNDPROC. For an example how to set the handler, see WM_CONTEXTMENU handling in Adding context menu to Inno Setup page.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...