我希望能够根据所选的特定组件禁用组件的选择。我无法通过嵌套组件来实现这一点,因为组件需要在其自身上进行选择,但如果选择了另一个特定组件则不能。目前,我使用显示消息的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;
问题是似乎没有一个事件允许它在用户选择或取消选择组件时动态更改。是否有一个事件我可以放置此代码或以其他方式执行此操作?
答案 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。