选择特定组件时,Inno Setup会禁用组件选择

时间:2015-06-24 12:23:02

标签: inno-setup

我希望能够根据所选的特定组件禁用组件的选择。我无法通过嵌套组件来实现这一点,因为组件需要在其自身上进行选择,但如果选择了另一个特定组件则不能。目前,我使用显示消息的NextButtonClick事件处理此问题:

if IsComponentSelected('Client') and IsComponentSelected('Sync') then
  begin
    MsgBox('A Client installation cannot have the Synchronisation component selected.',
      mbError, MB_OK);
      Result := False;      
  end;

阻止用户继续取消选择不兼容的组合。但是,如果我可以简单地禁用组件的选择而不是显示消息,那将会更加优雅:

if CurPageID = wpSelectComponents then
  begin
    if IsComponentSelected('Client') then
      begin
        WizardForm.ComponentsList.Checked[15] := False;
        WizardForm.ComponentsList.ItemEnabled[15] := False;
      end
    else
      begin
        WizardForm.ComponentsList.ItemEnabled[15] := True;
      end;
  end;

问题是似乎没有一个事件允许它在用户选择或取消选择组件时动态更改。是否有一个事件我可以放置此代码或以其他方式执行此操作?

2 个答案:

答案 0 :(得分:1)

你有TLama的解决方案可能比以下更好,但这段代码仍然是实现目标的一种方式(虽然你需要innocallback.dll):

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program

[Files]
Source: ".\InnoCallback.dll"; DestDir: "{tmp}"; Flags: dontcopy nocompression

[Components]
Name: "Client"; Description: "Client"; Types: custom
Name: "Sync"; Description: "Sync"; Types: custom

[Code]
var
TimerID: Integer;

type
TTimerProc = procedure(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; 
SysTime: DWORD);
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:InnoCallback.dll stdcall';    
function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
lpTimerFunc: UINT): UINT; external 'SetTimer@user32.dll stdcall';

function KillTimer(hWnd: HWND; uIDEvent: UINT): BOOL; 
external 'KillTimer@user32.dll stdcall'; 

procedure KillComponentsTimer;
begin
  if TimerID <> 0 then 
    begin
      if KillTimer(0, TimerID) then
        TimerID := 1;
    end;
end;

procedure OnComponentsCheck(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; 
SysTime: DWORD);
begin
    if IsComponentSelected('Client') then begin
        WizardForm.ComponentsList.Checked[1] := False;
        WizardForm.ComponentsList.ItemEnabled[1] := False;
    end
    else begin
        WizardForm.ComponentsList.ItemEnabled[1] := True;
    end;    
    if IsComponentSelected('Sync') then begin
        WizardForm.ComponentsList.Checked[0] := False;
        WizardForm.ComponentsList.ItemEnabled[0] := False;
    end
    else begin 
        WizardForm.ComponentsList.ItemEnabled[0] := True;
    end;
end;

procedure ComponentsCheck();
var
  TimerCallback: LongWord;
begin
  TimerCallback := WrapTimerProc(@OnComponentsCheck, 4);
  TimerID := SetTimer(0, 0, 100, TimerCallback);
end;

procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpSelectComponents then
  begin
    ComponentsCheck;
  end;
if CurPageID = not wpSelectComponents then 
  begin
   KillComponentsTimer;
  end;
end;

答案 1 :(得分:1)

我最后使用的代码完全基于他之前提供的@ TLama代码,因为这不需要使用外部DLL。

[Code]
const
//Define global constants
  CompIndexSync = 15;
  CompIndexSyncClient = 16;
  CompIndexSyncServer = 17;

var
//Define global variables
  CompPageVisited: Boolean;
  DefaultCompClickCheck: TNotifyEvent;
  DefaultCompTypeChange: TNotifyEvent;

//Uncheck and set the enabled state of the Sync components based on whether the Client component is selected
procedure UpdateComponents;
begin
  with WizardForm.ComponentsList do
    begin
      if IsComponentSelected('Client') then
        begin
          CheckItem(CompIndexSync, coUncheck);
        end; 
      ItemEnabled[CompIndexSync] := not IsComponentSelected('Client');
      ItemEnabled[CompIndexSyncClient] := not IsComponentSelected('Client');
      ItemEnabled[CompIndexSyncServer] := not IsComponentSelected('Client');
      Invalidate; //required for text state to update correctly
    end;
end;

//Update the component states if the component states change and restore the original event handler procedures
procedure ComponentsClickCheck(Sender: TObject);
begin
  DefaultCompClickCheck(Sender);
  UpdateComponents;
end;

procedure ComponentsTypesComboChange(Sender: TObject);
begin
  DefaultCompTypeChange(Sender);
  UpdateComponents;
end;

procedure InitializeWizard();
begin
//Store the original Components Page OnClickCheck and Types Combo Box OnChange event procedures and assign custom procedures
  DefaultCompClickCheck := WizardForm.ComponentsList.OnClickCheck;
  WizardForm.ComponentsList.OnClickCheck := @ComponentsClickCheck;
  DefaultCompTypeChange := WizardForm.TypesCombo.OnChange;
  WizardForm.TypesCombo.OnChange := @ComponentsTypesComboChange;
end;

procedure CurPageChanged(CurPageID: Integer);
begin
//Update the Components Page if entered for the first time
  if (CurPageID = wpSelectComponents) and not CompPageVisited then
    begin
      CompPageVisited := True;
      UpdateComponents;
    end;
end;

虽然这个和@ RobeN的解决方案都有效,但它们都表现出图形更新问题,即当将组件的状态从活动状态更改为禁用状态,反之亦然时,在拖动滚动条之前,文本不会自动变暗或变暗

请注意,通过添加“Invalidate;”来解决上述刷新问题。线。上面更新的代码带有注释以反映这一点。有关详细信息,请参阅Inno Setup Components graphical refresh issue。谢谢@TLama。