代码之家  ›  专栏  ›  技术社区  ›  Robert Wigley

Inno Setup选中另一个任务时取消选中该任务

  •  2
  • Robert Wigley  · 技术社区  · 8 年前

    我正试图拦截 WizardForm.TasksList.OnClickCheck 事件,以便在选择另一个任务时取消选中该任务。我知道在这种情况下通常会使用单选按钮,但在选择另一个任务时自动取消选中一个任务在这里效果更好,因为使用了多个分层任务,而且如果使用单选钮,则在任务子树的顶部总是必须选择两个任务中的一个。为了保持一致性,重新设计任务层次结构是不可行的,因为这将包括两个临时任务,这些任务将在安装程序的未来版本中删除。为此,我写了以下内容:

    var
      DefaultTasksClickCheck: TNotifyEvent;
    
    { Uncheck tasks based on what other tasks are selected }
    procedure UpdateTasks();
    var
      intIndex: Integer;
    begin
      with WizardForm.TasksList do
        begin
          if IsTaskSelected('Task1') then
            begin
              intIndex := WizardForm.TasksList.Items.IndexOf('Task36 Description');
              CheckItem(intIndex, coUncheck);
            end;
          if IsTaskSelected('Task36') then
            begin
              intIndex := WizardForm.TasksList.Items.IndexOf('Task1 Description');
              CheckItem(intIndex, coUncheck);
            end;
        end;
    end;
    
    { Update the task states if the task states change and restore the original event handler procedure }
    procedure TasksClickCheck(Sender: TObject);
    begin
      DefaultTasksClickCheck(Sender);
      UpdateTasks;
    end;
    
    procedure InitializeWizard();
    begin
      { Store the original Tasks Page OnClickCheck event procedure and assign custom procedure }
      DefaultTasksClickCheck := WizardForm.TasksList.OnClickCheck;
      WizardForm.TasksList.OnClickCheck := @TasksClickCheck;
    end;
    

    然而,当我运行代码时,我得到一个:

    超出程序范围

    错误,单击任何复选框时 DefaultTasksClickCheck(Sender); 突出显示为违规行。如果我注释掉这一行,我就不会再收到错误,但显然不再恢复原始事件处理程序,它仍然无法正确地检查和取消选中任务,当选中Task1时,Task36处于不选中状态。我做错了什么?

    1 回复  |  直到 8 年前
        1
  •  2
  •   Martin Prikryl    5 年前
    1. 这个 WizardForm.TasksList.OnClickCheck 不是由Inno设置本身指定的(与 WizardForm.ComponentsList.OnClickCheck ),所以您不能调用它。

      要解决此问题,请执行以下操作之一:

      • 完全移除 DefaultTasksClickCheck ;
      • 或者,如果您希望在Inno Setup的未来版本中开始使用该事件,请检查它是否 nil 在调用之前。
    2. 您无法知道最近在 OnClickCheck 处理程序。因此,您必须记住以前检查过的任务,才能正确决定要取消选择的任务。

    [Tasks]
    Name: Task1; Description: "Task1 Description"
    Name: Task36; Description: "Task36 Description"; Flags: unchecked
    
    [Code]
    
    var
      DefaultTasksClickCheck: TNotifyEvent;
      Task1Selected: Boolean;
    
    procedure UpdateTasks;
    var
      Index: Integer;
    begin
      { Task1 was just checked, uncheck Task36 }
      if (not Task1Selected) and IsTaskSelected('Task1') then
      begin
        Index := WizardForm.TasksList.Items.IndexOf('Task36 Description');
        WizardForm.TasksList.CheckItem(Index, coUncheck);
        Task1Selected := True;
      end
        else 
      { Task36 was just checked, uncheck Task1 }
      if Task1Selected and IsTaskSelected('Task36') then
      begin
        Index := WizardForm.TasksList.Items.IndexOf('Task1 Description');
        WizardForm.TasksList.CheckItem(Index, coUncheck);
        Task1Selected := False;
      end;
    end;
    
    procedure TasksClickCheck(Sender: TObject);
    begin
      if DefaultTasksClickCheck <> nil then
        DefaultTasksClickCheck(Sender);
      UpdateTasks;
    end;
    
    procedure CurPageChanged(CurPageID: Integer);
    begin
      if CurPageID = wpSelectTasks then
      begin
        { Only now is the task list initialized, check what is the current state }
        { This is particularly important during upgrades, }
        { when the task does not have its default state }
        Task1Selected := IsTaskSelected('Task1');
      end;
    end;
    
    procedure InitializeWizard();
    begin
      DefaultTasksClickCheck := WizardForm.TasksList.OnClickCheck;
      WizardForm.TasksList.OnClickCheck := @TasksClickCheck;
    end;
    

    在Inno Setup 6中,您也可以使用任务名称和 WizardIsTaskSelected WizardSelectTasks 。有关示例,请参见 Inno Setup: how to auto select a component if another component is selected? .


    有关检测已检查项目的更通用解决方案,请参阅 Inno Setup Detect changed task/item in TasksList.OnClickCheck event .