Inno Setup Components graphical refresh issue

后端 未结 1 667
一向
一向 2021-01-14 09:54

Following on from my question Inno Setup disable component selection when a specific component is selected, both solutions exhibit a problem whereby the component list does

相关标签:
1条回答
  • 2021-01-14 10:32

    The problem is in the way the ItemEnabled setter invalidates the item. Instead of invalidating the whole item rectangle it calls the InvalidateCheck method which invalidates only the check box portion of the item. See this code (commented by me):

    procedure TNewCheckListBox.InvalidateCheck(Index: Integer);
    var
      IRect: TRect;
    begin
      // store the full item rectangle into the IRect variable
      IRect := ItemRect(Index);
      // offset this stored rectangle's left position by the item level
      Inc(IRect.Left, (FCheckWidth + 2 * Offset) * (ItemLevel[Index]));
      // set its right position to the left edge + width of the check image + margin offsets,
      // but with no item text consideration, because this method was intended to invalidate
      // just the check box portion of the item which is not enough for enabled state change
      IRect.Right := IRect.Left + (FCheckWidth + 2 * Offset);
      // flip the rectangle for RTL reading and ask the control to invalidate that rectangle
      FlipRect(IRect, ClientRect, FUseRightToLeft);
      InvalidateRect(Handle, @IRect, FThemeData <> 0);
    end;
    

    The enabled state setter would need to have something like this (pseudo-code):

    procedure TNewCheckListBox.SetItemEnabled(Index: Integer; const AEnabled: Boolean);
    begin
      if ItemStates[Index].Enabled <> AEnabled then
      begin
        ItemStates[Index].Enabled := AEnabled;
        // invalidate the check portion of the item
        InvalidateCheck(Index);
        // and invalidate also the text portion of the item
        InvalidateText(Index);
      end;
    end;
    

    So this is a bug in the TNewCheckListBox control. Because there is no access to the item rectangles, you can ask the whole control to invalidate by calling Invalidate when you finish updating the enabled state of the item(s):

    procedure UpdateComponents;
    begin
      with WizardForm.ComponentsList do
      begin
        ...
        ItemEnabled[CompIndexSync] := not IsComponentSelected('Client');
        ItemEnabled[CompIndexSyncClient] := not IsComponentSelected('Client');
        ItemEnabled[CompIndexSyncServer] := not IsComponentSelected('Client');
        ...
        Invalidate;
      end;
    end;
    
    0 讨论(0)
提交回复
热议问题