Results 1 to 13 of 13

Thread: Virtual (easy)listview

  1. #1
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289

    Virtual (easy)listview

    Hoi

    Ik heb een probleem in mijn applicatie waarbij de items niet goed geladen worden, of wellicht niet goed opgeruimd.

    Ik lees een ';'-seperated bestand in:
    Code:
    TestFile.CSV
    ;Col1,Col2,Col3,Col4,profile
    test1a;test1b;test1c;blah1;prof1
    test2a;test2b;test2c;blah2;prof2
    test3a;test3b;test3c;blah3;prof1
    Het inlezen gaat prima voor de eerste keer, daarna krijg ik de volgende issues:
    1. Toevoegen regel aan TestFile.CSV (middels Edit button, gevolgd door een reload button)
      Click image for larger version. 

Name:	Added.PNG 
Views:	69 
Size:	16.9 KB 
ID:	8168
    2. Verwijderen regel uit TestFile.CSV (middels Edit button, gevolgd door een reload button)
      Click image for larger version. 

Name:	remove.PNG 
Views:	71 
Size:	16.0 KB 
ID:	8169
    3. Reload zonder edit zorgt voor extra entries
      Click image for larger version. 

Name:	reload.PNG 
Views:	70 
Size:	15.3 KB 
ID:	8170


    Ik vermoed dat het ergens in de ObjectList mis gaat maar ben er nu al een tijd op aan het puzzelen maar zie niet waar het mis gaat.
    Het valt me op dat de OBJ counter in het memo niet dezelfde items aangeeft als wat er in de EasyListview (ELV) staat.

    Heb het geheel even in een test applicatie gezet wat het makkelijk reproduceerd.
    ZipFile ELVtest.zip

    Code:
    unit uTest;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls, MPCommonObjects, EasyListview, System.Contnrs,
      System.IOUtils, Winapi.ShlObj, Winapi.ShellAPI;
    
    type
      TCSVFileItem                = class
      private
        FCol1                     : string;
        FCol2                     : string;
        FCol3                     : string;
        FCol4                     : string;
        FProfile                  : string;
      public
        property Col1             : string    read FCol1;
        property Col2             : string    read FCol2;
        property Col3             : string    read FCol3;
        property Col4             : string    read FCol4;
        property Profile          : string    read FProfile;
      end;
    
    
      TForm1                      = class(TForm)
        ELV                       : TEasyListview;
        PanelTop                  : TPanel;
        btReload                  : TSpeedButton;
        btEdit                    : TSpeedButton;
        cbProfileFilter           : TComboBox;
        edFilter                  : TEdit;
        Memo1                     : TMemo;
        procedure ELVItemGetCaption (Sender: TCustomEasyListview; Item: TEasyItem; Column: Integer; var Caption: WideString);
        procedure FormCreate        (Sender: TObject);
        procedure FormDestroy       (Sender: TObject);
        procedure edFilterChange    (Sender: TObject);
        procedure btReloadClick     (Sender: TObject);
        procedure btEditClick       (Sender: TObject);
        procedure cbProfileFilterChange(Sender: TObject);
      private
        { Private declarations }
        FCSVFileItemObjList       : TObjectList;
        FActiveListItems          : TList;
        FStringListItems          : TStringList;
        FStringListGroups         : TStringList;
      public
        { Public declarations }
        FCsvFile                  : string;
        procedure AddCSVFileItem    (const aCol1, aCol2, aCol3, aCol4, aProfile: string);
        procedure ApplyFilter       (const aFilter : string; aGroupsItemIndex : integer);
        procedure FileOpen;
      end;
    
    function GetSpecialFolderPath(CSIDLFolder: Integer): string;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FCsvFile            := '.\TestFile.CSV';
      FCSVFileItemObjList := TObjectList.Create;
      FActiveListItems    := TList.Create;
      FStringListItems    := TStringList.Create;
    
      FStringListGroups   := TStringList.Create;
      with FStringListGroups do
        begin
          Sorted        := true;
          Duplicates    := dupIgnore;
        end;
    
      FileOpen;
    end;
    
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      FStringListItems.Free;
      FStringListGroups.Free;
      FActiveListItems.Free;
      FCSVFileItemObjList.Free;
    end;
    
    procedure TForm1.ELVItemGetCaption(Sender: TCustomEasyListview; Item: TEasyItem; Column: Integer; var Caption: WideString);
    var
      CSVFileItem: TCSVFileItem;
    begin
     CSVFileItem    := FActiveListItems[Item.Index];
      case Column of
        0: Caption := CSVFileItem.Col1;
        1: Caption := CSVFileItem.Col2;
        2: Caption := CSVFileItem.Col3;
        3: Caption := CSVFileItem.Col4;
        4: Caption := CSVFileItem.Profile;
      end;
    end;
    
    
    procedure TForm1.AddCSVFileItem(const aCol1, aCol2, aCol3, aCol4, aProfile: string);
    var
      CSVFileItem: TCSVFileItem;
    begin
      CSVFileItem := TCSVFileItem.Create;
      try
        CSVFileItem.FCol1     := aCol1;
        CSVFileItem.FCol2     := aCol2;
        CSVFileItem.FCol3     := aCol3;
        CSVFileItem.FCol4     := aCol4;
        CSVFileItem.FProfile  := aProfile;
    
        FCSVFileItemObjList.Add(CSVFileItem);
      except
        CSVFileItem.Free;
      end;
    end;
    
    procedure TForm1.ApplyFilter(const aFilter : string; aGroupsItemIndex : integer);
    var
      I: Integer;
    begin
      ELV.BeginUpdate;
      try
        ELV.Items.Clear;
        FActiveListItems.Clear;
        for I := 0 to FCSVFileItemObjList.Count - 1 do
          begin
            if cbProfileFilter.Items[aGroupsItemIndex] = 'Show All' then
              begin
                if (aFilter = '')
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col1)) <> 0)
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col2)) <> 0)
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col3)) <> 0)
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col4)) <> 0)
                then
                  FActiveListItems.Add(FCSVFileItemObjList[I]);
              end
            else
              begin
                if ((aFilter = '')
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col1)) <> 0)
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col2)) <> 0)
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col3)) <> 0)
                or (Pos(UpperCase(aFilter), UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Col4)) <> 0))
                and (UpperCase(cbProfileFilter.Items[aGroupsItemIndex]) = UpperCase(TCSVFileItem(FCSVFileItemObjList[I]).Profile)) then
                  FActiveListItems.Add(FCSVFileItemObjList[I]);
              end;
          end;
    
        for I := 0 to FActiveListItems.Count -1 do
          ELV.Items.AddVirtual;
    
      finally
        ELV.EndUpdate;
      end;
    end;
    
    procedure TForm1.btEditClick(Sender: TObject);
    var
      ExeFile : string;
    begin
      ExeFile := IncludeTrailingPathDelimiter(GetSpecialFolderPath(CSIDL_WINDOWS)) + 'notepad.exe';
    
      if TFile.Exists (ExeFile) then
        begin
          ShellExecute( Handle,
                        'open',
                        PChar(ExeFile),
                        PChar(FCsvFile),
                        nil,
                        SW_SHOWNORMAL );
        end;
    end;
    
    procedure TForm1.btReloadClick(Sender: TObject);
    begin
      FileOpen;
    end;
    
    procedure TForm1.cbProfileFilterChange(Sender: TObject);
    begin
      ApplyFilter(edFilter.Text, cbProfileFilter.ItemIndex);
    end;
    
    procedure TForm1.edFilterChange(Sender: TObject);
    begin
      ApplyFilter(edFilter.Text, cbProfileFilter.ItemIndex);
    end;
    
    procedure TForm1.FileOpen;
    var
      I       : Integer;
      S       : String;
      SArray  : TArray<String>;
    begin
      if TFile.Exists(FCSVFile) then
        begin
          FStringListItems.LoadFromFile(FCSVFile);
          if FStringListItems.Count <> -1 then
            begin
              ELV.Items.Clear;
              FStringListGroups.Clear;
              ELV.BeginUpdate;
              try
                for I := 0 to FStringListItems.Count -1 do
                  begin
                    S := FStringListItems[I];
                    if (not S.StartsWith(';'))  AND (not S.IsEmpty) AND
                       (not S.IsNullOrEmpty(S)) AND (not S.IsNullOrWhiteSpace(S)) then
                      begin
                        SArray := S.Split([';']);
                        if Length(SArray) = ELV.Header.Columns.Count then
                          begin
                            AddCSVFileItem (SArray[0], SArray[1], SArray[2], SArray[3], SArray[4]);
                            ELV.Items.AddVirtual;
                            FStringListGroups.Add(SArray[4]);
    
                            Memo1.Lines.Add(format('ItemCounter=%d | ELV=%d | OBJ=%d | Active=%d ',[I, ELV.Items.Count, FCSVFileItemObjList.Count, FActiveListItems.Count]));
                          end
                            else
                              ShowMessage (format('Invalid line: "%s"',[S]));
                      end;
                  end;
              finally
                ELV.EndUpdate();
              end;
              Memo1.Lines.Add('================================================================================');
              cbProfileFilter.Items := FStringListGroups;
              cbProfileFilter.Items.Insert(0, 'Show All');
              cbProfileFilter.ItemIndex := 0;
              ApplyFilter(edFilter.Text, cbProfileFilter.ItemIndex);
            end;
        end;
    end;
    
    function GetSpecialFolderPath(CSIDLFolder: Integer): string;
    var
       FilePath: array [0..MAX_PATH] of char;
    begin
      SHGetFolderPath(0, CSIDLFolder, 0, 0, FilePath);
      Result := FilePath;
    end;
    
    
    end.

    Ik hoop dat er iemand hier tijd en zin heeft om eens naar mijn geknutsel te kijken en me een zetje in de juiste richting kan geven, want wat ik ook probeer, een echt suc6 wordt het allemaal nog niet.

    Alvast bedankt.
    Herby

  2. #2
    De foutmelding die je krijgt heeft maken dat er geprobeerd wordt om element uit een lijst te halen dat niet bestaat op dat moment. Als je een paar breakpoints in je code zet en door je code heen stept dan zou je vrij snel moeten kunnen zien waar het misgaat.

  3. #3
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    Het probleem zit hem in de TObjectList waar (bij 1 item in de file) er na een refresh er twee in zitten, dit zou gelijk moeten zijn aan het aantal items in de file.
    Als ik in de FileOpen dan "FCSVFileItemObjList.Clear;" plaats dan krijg ik een access denied ($C000005).

  4. #4
    $C000005 krijg ik ook nog weleens. Volgens mij is dat een bekende als je een bepaalde property of (virtual?) method wilt aanroepen van een object dat nil is.

    Voor zover ik kan zien worden in FileOpen niet alle lists leeggemaakt, en daar zit denk ik ook het probleem. FCSVFileItemObjList kan alleen maar groeien. Bij herladen staat dus de nieuwe content van de file achter de vorige content in diezelfde list. Als je verwacht dat andere lists hetzelfde aantal items hebben, kom je bedrogen uit.
    Dus: De makkelijkste fix: Zorg dat je alle data weggooit uit alle lijsten aan het begin van FileOpen. Heropenen zorgt dan dat je de hele file opnieuw inlaadt.
    "FCSVFileItemObjList.Clear" zou het wel degelijk moeten doen. Waar in FileOpen heb je die neergezet?
    1+1=b

  5. #5
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    In de try/finally van fileopen.

    ELV.Items.Clear;
    FActiveListItems.Clear;
    FCSVFileItemObjList.Clear;

    Eerste keer gaat het goed maar met de reload krijg ik de C000005

  6. #6
    $C000005 is een typisch voorbeeld van een fout die overal kan zitten. Dus een aanroep naar een al vrijgegeven object buiten het spectrum van het programma dus 2e of 3e lijn. Zet een breakpoint bij Destroy form. Zoek zo het probleem op.

  7. #7
    Je gooit FActiveListItems ook niet leeg, maar wel in de versie die fout gaat.
    Het ophalen van de caption maakt gebruik van FActiveListItems. Zit het probleem daar niet in?

    Verder wat algemene opmerkingen: ELV.Items.Clear; is mogelijk (veel) trager dan ELV.Clear, zie hier.
    In plaats van steeds AddVirtual te doen, is het niet efficienter om in één keer een count te zetten als je die eenmaal hebt bepaald?

    Verder, waar komt de EasyListView vandaan? Is die er ook voor Lazarus? Ik zou het best willen testen, maar ik kan dat ding niet vinden.
    1+1=b

  8. #8
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    Zal morgen nog eens kijken, mustangpeak easylistview zit gewoon in getit en is ook te vinden bij Turbopack op GitHub.

  9. #9
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    Quote Originally Posted by GolezTrol View Post
    Je gooit FActiveListItems ook niet leeg, maar wel in de versie die fout gaat.
    Het ophalen van de caption maakt gebruik van FActiveListItems. Zit het probleem daar niet in?

    Verder wat algemene opmerkingen: ELV.Items.Clear; is mogelijk (veel) trager dan ELV.Clear, zie hier.
    In plaats van steeds AddVirtual te doen, is het niet efficienter om in één keer een count te zetten als je die eenmaal hebt bepaald?

    Verder, waar komt de EasyListView vandaan? Is die er ook voor Lazarus? Ik zou het best willen testen, maar ik kan dat ding niet vinden.
    Voor zover ik het nu kan bepalen lijkt het door de ObjectList te komen, die heeft na een reload een count van 2, probleem is dat als ik die clear in de FileOpen dan krijg ik $C000005.
    Ik had ook al FActiveListItems erbij gezet, wordt het niet beter van.

    Zie gewoon niet waar het fout gaat.

    Code:
          // $C000005                 FCSVFileItemObjList.Clear;
          // Listindex out of bound   FActiveListItems.Clear;
          FStringListItems.LoadFromFile(FCSVFile);
          if FStringListItems.Count <> -1 then
            begin
              ELV.Items.Clear;
              FStringListGroups.Clear;
    In EasyListview is er geen ELV.Clear, ELV.Items.clear lijkt me dan de juiste methode.

    https://github.com/TurboPack/Mustang.../Basic/Virtual
    In deze demo (en in de FULL Demo) staat een voorbeeld van hoe het virtual moet.

    Ik gebruik de D10.3.3 Community Edition dus heb hem geinstalleerd via GetIt.

    Persoonlijk vind ik ELV veel krachtiger dan de standaard LV.

    Gr
    Herby

  10. #10
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    pfffffff ik ben er uit.

    Het probleem zat hem in het FileOpen gedeelte waarbij ik de items virtual aan de listview toevoeg.
    Dit doe ik ook al in het filter om te laten zien wat ik wil.
    Door de AddVirtual te verwijderen is het probleem opgelost en kunnen de twee andere regels zonder $C000005 uitgevoerd worden.

    Code:
    procedure TForm1.FileOpen;
    var
      I       : Integer;
      S       : String;
      SArray  : TArray<String>;
    begin
      if TFile.Exists(FCSVFile) then
        begin
          FCSVFileItemObjList.Clear;
          FActiveListItems.Clear;
          FStringListItems.LoadFromFile(FCSVFile);
          if FStringListItems.Count <> -1 then
            begin
              ELV.BeginUpdate;
              ELV.Items.Clear;
             FStringListGroups.Clear;
              try
                for I := 0 to FStringListItems.Count -1 do
                  begin
                    S := FStringListItems[I];
                    if (not S.StartsWith(';'))  AND (not S.IsEmpty) AND
                       (not S.IsNullOrEmpty(S)) AND (not S.IsNullOrWhiteSpace(S)) then
                      begin
                        SArray := S.Split([';']);
                        if Length(SArray) = ELV.Header.Columns.Count then
                          begin
                            AddCSVFileItem (SArray[0], SArray[1], SArray[2], SArray[3], SArray[4]);
                           // ELV.Items.AddVirtual;
                            FStringListGroups.Add(SArray[4]);
                          end
                            else
                              ShowMessage (format('Invalid line: "%s"',[S]));
                      end;
                  end;
              finally
                ELV.EndUpdate();
              end;
              cbProfileFilter.Items := FStringListGroups;
              cbProfileFilter.Items.Insert(0, 'Show All');
              cbProfileFilter.ItemIndex := 0;
              ApplyFilter(edFilter.Text, cbProfileFilter.ItemIndex);
            end;
        end;
    end;
    In ieder geval, bedankt voor het meedenken

  11. #11
    Delphi Code:
    1. if FStringListItems.Count <> -1

    Count kan < 0 zijn?
    Dat is een beetje contra intuitief voor mij.

    Bart

  12. #12
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    Quote Originally Posted by Bart B View Post
    Delphi Code:
    1. if FStringListItems.Count <> -1

    Count kan < 0 zijn?
    Dat is een beetje contra intuitief voor mij.

    Bart
    < 0 is prima is inderdaad ook prima, ongelijk aan -1 ook :-)

  13. #13
    Maar hoe kan Count ooit kleiner dan nul zijn?
    FStringListItems is een TStringList voor zover ik kan zien.
    Als het geen items bevat, dan is Count nul.
    Je kunt dan niet nog meer (niet bestaande) items verwijderen, zodat het aantal items negatief wordt.

    Bart

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •