Search code examples
inno-setuppascalscript

How to access the ItemIndex property of the TNewComboBox class?


Goal

I'm helping out a friend make an installer using Inno Setup in Conjunction with VCL-Styles plugin. I currently trying to access an index which is supposedly linked to each choice in a combo box and for that I use the TNewComboBox.ItemIndex.

Error

For some reason, accessing / returning the property doesn't work for us and we recieve this error:

enter image description here

Code

Here is the code

Source:  "C:\Program Files (x86)\The Road To Delphi\VCL Styles Inno\VclStylesinno.dll"; DestDir: "{app}";
var
    cb: TNewComboBox;

procedure DropDownChange(Sender : TObject );
begin
    case cb.ItemIndex of  // <------- Error line 76 "Could not Call proc"
        0:
        begin
            Delete(cfgStr, Pos(cvar, cfgStr) + Length(cvar), 1);
            Insert('0', cfgStr, Pos(cvar, cfgStr) + Length(cvar));
        end;
        1:
        begin
            Delete(cfgStr, Pos(cvar, cfgStr) + Length(cvar), 1);
            Insert('1', cfgStr, Pos(cvar, cfgStr) + Length(cvar));
        end;
        2:
        begin
            Delete(cfgStr, Pos(cvar, cfgStr) + Length(cvar), 1);
            Insert('2', cfgStr, Pos(cvar, cfgStr) + Length(cvar));
        end;
        3:
        begin
            Delete(cfgStr, Pos(cvar, cfgStr) + Length(cvar), 1);
            Insert('3', cfgStr, Pos(cvar, cfgStr) + Length(cvar));
        end;
        4:
        begin
            Delete(cfgStr, Pos(cvar, cfgStr) + Length(cvar), 1);
            Insert('4', cfgStr, Pos(cvar, cfgStr) + Length(cvar));
        end;
        5:
        begin
            Delete(cfgStr, Pos(cvar, cfgStr) + Length(cvar), 1);
            Insert('0', cfgStr, Pos(cvar, cfgStr) + Length(cvar));
        end;
    end
end;

procedure CreateDropDown(page: TWizardPage; caption: String; cb: TNewComboBox; cvar: String; index: Integer; item0, item1, item2, item3, item4, item5 : String);
var
    newLabel: TLabel;
begin
    newLabel:= TLabel.Create(page);
    newLabel.Parent:= page.Surface;
    newLabel.Caption:= caption;
    case page of
        SettingsPageA:
        begin
            newLabel.Left:= curWidthA;
            newLabel.Top:= curHeightA;
            case curWidthA of
                0:
                begin
                    curWidthA:= curWidthA + 264;
                end;
                264:
                begin
                    curWidthA:= curWidthA + 264;
                end;
                528:
                begin
                    curWidthA:= 0;
                    curHeightA:= curHeightA + 66;
                end;
            end;
        end;
        SettingsPageB:
        begin
            newLabel.Left:= curWidthB;
            newLabel.Top:= curHeightB;
            case curWidthB of
                0:
                begin
                    curWidthB:= curWidthB + 264;
                end;
                264:
                begin
                    curWidthB:= curWidthB + 264;
                end;
                528:
                begin
                    curWidthB:= 0;
                    curHeightB:= curHeightB + 66;
                end;
            end;
        end;
        SettingsPageC:
        begin
            newLabel.Left:= curWidthC;
            newLabel.Top:= curHeightC;
            case curWidthC of
                0:
                begin
                    curWidthC:= curWidthC + 264;
                end;
                264:
                begin
                    curWidthC:= curWidthC + 264;
                end;
                528:
                begin
                    curWidthC:= 0;
                    curHeightC:= curHeightC + 66;
                end;
            end;
        end;
    end;
    newLabel.Width:= 247;
    newLabel.Height:= 25;
    newLabel.Transparent:= True;
    
    cb:= TNewComboBox.Create(page);
    cb.Parent:= page.Surface;
    cb.Left:= newLabel.Left;
    cb.Top:= newLabel.Top + newLabel.Height + 4;
    cb.Width:= newLabel.Width;
    cb.Height:= newLabel.Height;
    cb.Style:= csDropDownList;
    cb.Items.Add(item0);
    if Length(item1) > 0 then
    begin
        cb.Items.Add(item1);
        if Length(item2) > 0 then
        begin
            cb.Items.Add(item2);
            if Length(item3) > 0 then
            begin
                cb.Items.Add(item3);
                if Length(item4) > 0 then
                begin
                    cb.Items.Add(item4);
                    if Length(item5) > 0 then
                    begin
                        cb.Items.Add(item5);
                    end;
                end;
            end;
        end;
    end;
  cb.ItemIndex := index;
  cb.OnChange:= @DropDownChange; <---------------
end;

This is just a piece of the code which performs an .OnChange whenever the combo box changes of choice / Index. Thanks!


I've been requested for a minimal example of reproducible code shown below

procedure DropDownChanged(Sender: TObject);
begin
    Log(IntToStr(cb.ItemIndex);
end;

procedure CreateDropDown(page: TWizardPage; caption: String; cb: TNewComboBox; cvar: String; index: Integer; item0, item1 : String);
var
    newLabel: TLabel;
begin
    newLabel:= TLabel.Create(page);
    newLabel.Parent:= page.Surface;
    newLabel.Caption:= caption;
    newLabel.Left:= curWidth;
    newLabel.Top:= curHeight;
    
    newLabel.Width:= 247;
    newLabel.Height:= 25;
    newLabel.Transparent:= True;
    
    cb:= TNewComboBox.Create(page);
    cb.Parent:= page.Surface;
    cb.Left:= newLabel.Left;
    cb.Top:= newLabel.Top + newLabel.Height + 4;
    cb.Width:= newLabel.Width;
    cb.Height:= newLabel.Height;
    cb.Style:= csDropDownList;
    cb.Items.Add(item0);
    cb.Items.Add(item1);
    cb.ItemIndex:= index;
    cb.OnChange:= DropDownChanged;
end;

And to execute it:

CreateDropDown(wpReady, 'Caption', 'ComboBox', 0, 'First Item', 'Second Item');

Edit 2

This is the original author of this little project. I've watered down the code necessary to recreate the issue, like this:

[Code]
var
    ExamplePage: TWizardPage;
    cb: TNewComboBox;

procedure DropDownChanged(Sender: TObject);
begin
    Log(IntToStr(cb.ItemIndex));
end;

procedure CreateDropDown(page: TWizardPage; cb: TNewComboBox; index: Integer; item0, item1 : String);
begin
    cb:= TNewComboBox.Create(page);
    cb.Parent:= page.Surface;
    cb.Style:= csDropDownList;
    cb.Items.Add(item0);
    cb.Items.Add(item1);
    cb.ItemIndex:= index;
    cb.OnChange:= @DropDownChanged;
end;

procedure CreateExamplePage;
var
    ExampleComboBox: TNewComboBox;
begin
    ExamplePage:= CreateCustomPage(wpWelcome, 'Example Page', 'This is an example');
    CreateDropDown(ExamplePage, ExampleComboBox, 0, 'First Item', 'Second Item');
end;

procedure InitializeWizard;
begin
    CreateExamplePage;
end;

This is the minimum required to reproduce the error upon selecting an item in the drop-down. I hope this helps clear out the issue!


Solution

  • You have name conflict between the global cb variable and local cb parameter of CreateDropDown function. You assign the local parameter (what makes little sense), while the global variable is never assigned. Plus, it's not really clear, what is the purpose of ExampleComboBox.

    Maybe you wanted something like this?

    [Code]
    var
      ExamplePage: TWizardPage;
      ExampleComboBox: TNewComboBox;
    
    procedure DropDownChanged(Sender: TObject);
    begin
      Log(IntToStr(ExampleComboBox.ItemIndex));
    end;
    
    function CreateDropDown(
      page: TWizardPage; index: Integer; item0, item1: String): TNewComboBox;
    begin
      Result := TNewComboBox.Create(page);
      Result.Parent:= page.Surface;
      Result.Style:= csDropDownList;
      Result.Items.Add(item0);
      Result.Items.Add(item1);
      Result.ItemIndex:= index;
      Result.OnChange:= @DropDownChanged;
    end;
    
    procedure CreateExamplePage;
    begin
      ExamplePage :=
        CreateCustomPage(wpWelcome, 'Example Page', 'This is an example');
    
      ExampleComboBox :=
        CreateDropDown(ExamplePage, 0, 'First Item', 'Second Item');
    end;
    
    procedure InitializeWizard;
    begin
      CreateExamplePage;
    end;
    

    The DropDownChanged does not have to rely on the global variable. If you want it to work for other comboboxes, rely on the Sender parameter instead

    Log(IntToStr(TNewComboBox(Sender).ItemIndex));