Solved

Getting Access Violation in Listview

Posted on 2011-09-18
5
1,489 Views
Last Modified: 2012-05-12
I am getting an Access Violation when importing a CSV file. The Stringlist leaves many white spaces in the tlistview after transferring the data from a Memo. What I want to know is why I am getting this access violation and is there a better way to go about this code to ellivate the extra loops i am putting the program through? Thanks! test.csv
procedure TForm1.Button1Click(Sender: TObject);

var
l,i,j : integer;
Lst : TStringList;

begin
Memo1.Lines.Clear;
ListView1.Items.Clear;
If OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);

Lst := TStringList.Create;
    Lst.LoadFromFile(OpenDialog1.FileName);
    Lst.Delete(0);
    Memo1.Lines.StrictDelimiter := True;
    Memo1.Lines.DelimitedText := Lst.Text;

for i := 0 to Memo1.Lines.Count do
If (Memo1.Lines[i] = '')then
Memo1.Lines.Delete(i);

for i := 0 to Memo1.Lines.Count do
    begin
      With ListView1.Items.Add do
      begin
        Caption := Memo1.Lines[i * ListView1.Columns.Count];
      for j := 1 to ListView1.Columns.Count do
      if ((i * ListView1.Columns.Count) + j) < (Memo1.Lines.Count) then
            SubItems.Add(Memo1.Lines[i * ListView1.Columns.Count + j])
          else
            Break;

for l := 1 to ListView1.Items.Count -1 do
If (ListView1.Items[i].Caption = '') then
ListView1.Items[i].Delete;

ListView1.Column[0].Width := -1;
ListView1.Column[1].Width := -1;
ListView1.Column[2].Width := -1;
ListView1.Column[3].Width := -1;
ListView1.Column[4].Width := 55;
ListView1.Column[5].Width := -1;
ListView1.Column[6].Width := -1;
ListView1.Column[7].Width := -1;


end;
end;
end;

Open in new window

0
Comment
Question by:DelphiNube
5 Comments
 
LVL 9

Accepted Solution

by:
Lester_Clayton earned 250 total points
ID: 36558421
for i := 0 to Memo1.Lines.Count do

Use for i := 0 to Pred(Memo1.Lines.Count) do

Explanation : if Lines.Count = 5 then your statement tries to do 6 lines (0, 1, 2, 3, 4, 5).  It will fail on the last one.

Be sure to change this on all applicable lines.

Also, be sure to do Lst.Free at the end to free up the allocated memory.

Finally, if you're going to delete items in a ListView, like you are, do it BACKWARDS.

Example:

for l := Pred(ListView1.Items.Count) downto 0 do

The reason is, if you have 10 items, and your program is going from item 0 to 9 (all 10), and it deletes item 2 - then item 9 is no longer valid.  If you delete item 4, then item 8 is no longer valid - it all moves up one.  Doing it backwards is much much safer.
0
 
LVL 25

Assisted Solution

by:epasquier
epasquier earned 250 total points
ID: 36558620
when you are going to delete items, and you still want the parsing to occurs in the normal way, you can use good old While loops
This is a strict equivalent to for i:=0 to Items.Count-1 do ... ;
i:=0;
While i<Items.Count do 
 begin
  ...
  Inc(i);
 end;

Open in new window

It will prevent potential problems when changing the Items list.

Specifically to your problem, you might not want to expand completely the CSV file, and delete the empty lines - that could delete an empty field, and make all of your code shifting the values.
Besides, that is not optimized

Instead, treat each CSV line one after the other. Only discard empty lines (and not empty fields)
Then, it is good idea to add even empty fields in the SubItems, to avoid testing the SubItems.Count each time you want to access a field from the listview.


procedure TForm1.Button1Click(Sender: TObject);
begin
 If OpenDialog1.Execute then
  ParseCSVFile(OpenDialog1.FileName);
end;

procedure TForm1.ParseCSVFile(FN:String);
var
 Lines, Values : TStringList;
 i,j:integer;
 L:String;
begin
 Lines:=TStringList.Create;
 Values:=TStringList.Create;
 
 ListView1.Items.BeginUpdate; // will prevent drawing of new items while building the list 
 try
  ListView1.Items.Clear;
  Lines.LoadFromFile(FN);
  Lines.Delete(0); // Delete first line of CSV file (Fields Header)
  i:=0;
  While i<Lines.Count do
   begin
    L:=Trim(Lines[i]); // get the line and trim leading/tailing spaces
    if L<> '' Then  // treat only not empty lines
     begin
      Values.DelimitedText:=Lines[i];  // Split this line values only
      if Values[0]<>'' Then // Will create only items with first field not empty
       With ListView1.Items.Add do
        begin
         Caption := Values[0];
         for j := 1 to ListView1.Columns.Count-1 do
          if j<Values.Count 
           Then SubItems.Add(Values[j])
           Else SubItems.Add(''); // Or break, but adding a SubItem even for empty fields 
           // can help later (you can avoid some "index out of bounds" exceptions 
           // by making sure that every item has the same number of subItems)
        end;
     end;   
    Inc(i);
   end;
 finally
  ListView1.Items.EndUpdate;   // will finally update the listview
  Lines.Free;
  Values.Free;
 end;  
// That should be done only once, maybe in OnFormCreate event 
 With ListView1 do
  begin 
   for i:=0 to 7 do Column[i].Width := -1; 
   Column[4].Width := 55; 
  end;    
end;

Open in new window

0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 36559066
why must you use math ?


Caption := Memo1.Lines[i * ListView1.Columns.Count];

Caption := Memo1.Lines[i];

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 36559264
because he expanded the whole CSV file  with this code Memo1.Lines.DelimitedText := Lst.Text;

L1C1,L1C2,L1C3
L2C1,L2C2,L2C3
=>
L1C1
L1C2
L1C3
L2C1
L2C2
L2C3

As I said, it's not a good idea, it makes the problem more complex and can create bugs if the CSV file has some lines with missing fields
0
 

Author Closing Comment

by:DelphiNube
ID: 36560606
Thanks fellow coders! Lester: You helped me use a system commend that I have never use that stabilized my code. epasquier: You helped me to use a routine that i'm very familiar with plus helped sustain the integrity of the existing code.

Thanks to both of you!
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Help on project with Soap 10 48
mapBully challenge 6 116
How To Loop - Python 19 80
Message not shown 5 34
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
When we want to run, execute or repeat a statement multiple times, a loop is necessary. This article covers the two types of loops in Python: the while loop and the for loop.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

863 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now