Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Getting Access Violation in Listview

Posted on 2011-09-18
5
Medium Priority
?
1,573 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 1000 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 1000 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 38

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

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

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

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
The viewer will learn how to implement Singleton Design Pattern in Java.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
Suggested Courses

916 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