Solved

Getting Access Violation in Listview

Posted on 2011-09-18
5
1,471 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 36

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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
mapBully challenge 6 88
How To Loop - Python 19 65
Delphi inherited method 6 36
Problem to open Excel file 15 38
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

708 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

14 Experts available now in Live!

Get 1:1 Help Now