为何我的Inno Setup脚本中组件预览图和描述无法加载?
问题修复方案
核心问题分析
你的代码存在两个主要问题:
- 按钮消失:不必要地修改了
OuterNotebook和InnerNotebook的高度,破坏了向导表单的锚定布局;同时在初始化阶段就修改了组件列表高度,导致保存的原始位置不正确。 - 预览/描述不加载:
FindControl函数可能无法正确识别嵌套的组件列表控件;HoverComponentChanged中未在鼠标离开时重置图片路径,导致逻辑错误。
修复后的完整代码
[Files] 部分(无需修改)
Source: "1.bmp"; Flags: dontcopy Source: "2.bmp"; Flags: dontcopy Source: "3.bmp"; Flags: dontcopy Source: "InnoCallback.dll"; Flags: dontcopy
[Components] 部分(无需修改)
Name: "Component1"; Description: "1*"; Types: Component1; Name: "Component2"; Description: "2*"; Types: Component2; Name: "Component3"; Description: "3*"; Types: Component3;
[Code] 部分(已修复)
var LastMouse: TPoint; type TTimerProc = procedure(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord); 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 WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord; external 'wrapcallback@files:InnoCallback.dll stdcall'; var CompLabel: TLabel; CompImage: TBitmapImage; LoadingImage: Boolean; procedure HoverComponentChanged(Index: Integer); var Description: string; Image: string; ImagePath: string; begin Image := ''; // 初始化图片路径为空 case Index of 0: begin Description := 'Component 1'; Image := '1.bmp'; end; 1: begin Description := 'Component 2'; Image := '2.bmp'; end; 2: begin Description := 'Component 3'; Image := '3.bmp'; end; else Description := 'Move your mouse over a component to see its description.'; end; CompLabel.Caption := Description; if Image <> '' then begin if not LoadingImage then begin LoadingImage := True; try ImagePath := ExpandConstant('{tmp}\' + Image); if not FileExists(ImagePath) then begin ExtractTemporaryFile(Image); end; CompImage.Bitmap.LoadFromFile(ImagePath); finally LoadingImage := False; end; end; CompImage.Visible := True; end else begin CompImage.Visible := False; end; end; procedure HoverTimerProc(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord); var P: TPoint; ClientP: TPoint; Index: Integer; begin GetCursorPos(P); if P <> LastMouse then begin LastMouse := P; // 直接检查鼠标是否在组件列表上,避免嵌套控件查找问题 ClientP := P; ScreenToClient(WizardForm.ComponentsList.Handle, ClientP); if PtInRect(WizardForm.ComponentsList.ClientRect, ClientP) then begin // 使用内置方法获取鼠标指向的列表项索引 Index := WizardForm.ComponentsList.ItemAtPos(ClientP, True); end else begin Index := -1; end; HoverComponentChanged(Index); end; end; type TPositionStorage = array of Integer; var CompPageModified: Boolean; CompPagePositions: TPositionStorage; procedure SaveComponentsPage(out Storage: TPositionStorage); begin SetArrayLength(Storage, 8); Storage[0] := WizardForm.Height; Storage[1] := WizardForm.NextButton.Top; Storage[2] := WizardForm.BackButton.Top; Storage[3] := WizardForm.CancelButton.Top; Storage[4] := WizardForm.ComponentsList.Height; Storage[5] := WizardForm.Bevel.Top; Storage[6] := WizardForm.BeveledLabel.Top; Storage[7] := WizardForm.ComponentsDiskSpaceLabel.Top; end; procedure LoadComponentsPage(const Storage: TPositionStorage; HeightOffset: Integer); begin if GetArrayLength(Storage) <> 8 then RaiseException('Invalid storage array length.'); WizardForm.Height := Storage[0] + HeightOffset; WizardForm.NextButton.Top := Storage[1] + HeightOffset; WizardForm.BackButton.Top := Storage[2] + HeightOffset; WizardForm.CancelButton.Top := Storage[3] + HeightOffset; // 仅在进入组件页面时调整列表高度 if HeightOffset > 0 then WizardForm.ComponentsList.Height := Storage[4] - CompLabel.Height - ScaleY(8) else WizardForm.ComponentsList.Height := Storage[4]; WizardForm.Bevel.Top := Storage[5] + HeightOffset; WizardForm.BeveledLabel.Top := Storage[6] + HeightOffset; WizardForm.ComponentsDiskSpaceLabel.Top := Storage[7] + HeightOffset; end; procedure InitializeWizard1(); var HoverTimerCallback: LongWord; begin HoverTimerCallback := WrapTimerProc(@HoverTimerProc, 4); SetTimer(0, 0, 50, HoverTimerCallback); CompLabel := TLabel.Create(WizardForm); CompLabel.Parent := WizardForm.SelectComponentsPage; CompLabel.Left := WizardForm.ComponentsList.Left; CompLabel.Width := WizardForm.ComponentsList.Width div 2; CompLabel.Height := ScaleY(64); CompLabel.Top := WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height + ScaleY(8); CompLabel.AutoSize := false; CompLabel.WordWrap := True; CompLabel.Anchors := [akLeft, akBottom]; // 锚定到左侧和页面底部 CompImage := TBitmapImage.Create(WizardForm); CompImage.Parent := WizardForm.SelectComponentsPage; CompImage.Top := CompLabel.Top; CompImage.Width := ScaleX(128); CompImage.Height := ScaleY(128); CompImage.Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width - CompImage.Width; CompImage.Anchors := [akRight, akBottom]; // 锚定到右侧和页面底部 end; procedure InitializeWizard2(); begin CompPageModified := False; end; procedure CurPageChanged(CurPageID: Integer); begin if CurPageID = wpSelectComponents then begin SaveComponentsPage(CompPagePositions); LoadComponentsPage(CompPagePositions, ScaleY(250)); CompPageModified := True; end else if CompPageModified then begin LoadComponentsPage(CompPagePositions, 0); CompPageModified := False; end; end; procedure InitializeWizard(); begin InitializeWizard1(); InitializeWizard2(); end;
关键修复点说明
- 移除不必要的控件高度修改:删除了对
OuterNotebook和InnerNotebook的高度调整,依赖向导表单的锚定布局自动适配高度变化。 - 调整组件列表高度时机:将组件列表高度的修改移至进入组件页面时,确保保存的是原始布局位置。
- 简化鼠标悬停检测:直接检查鼠标是否在组件列表控件范围内,使用内置
ItemAtPos方法获取列表项索引,避免嵌套控件查找的潜在问题。 - 修复图片路径重置逻辑:在
HoverComponentChanged中初始化图片路径为空,确保鼠标离开组件时隐藏预览图。 - 添加控件锚定:为描述标签和预览图设置锚定属性,确保表单高度变化时控件位置正确。
内容的提问来源于stack exchange,提问作者Lilith Helsente
相关产品推荐
相关产品推荐

