2007. március 7., szerda

Save and load TListView items to / from a file


Problem/Question/Abstract:

I would like to know how to save TListView items and subitems into a file and reload them into the listview on a button click or the next time the program starts.

Answer:

Solve 1:

The answer depends on what information you need to save and restore: only the strings or also image indices, if the latter, which indices? If it's only the strings one could do it this way:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls,
    StdCtrls;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    SaveButton: TButton;
    ClearButton: TButton;
    LoadButton: TButton;
    procedure ClearButtonClick(Sender: TObject);
    procedure SaveButtonClick(Sender: TObject);
    procedure LoadButtonClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{
Function IScan:
Parameters:
ch: Character to scan for
S : String to scan
fromPos: first character to scan
Returns: position of next occurence of character ch, or 0, if none found
Description: Search for next occurence of a character in a string
Error Conditions: none
Created: 11/27/96 by P. Below
}

function IScan(ch: Char; const S: string; fromPos: Integer): Integer;
var
  i: Integer;
begin
  Result := 0;
  for i := fromPos to Length(S) do
  begin
    if S[i] = ch then
    begin
      Result := i;
      Break;
    end;
  end;
end;

{
Procedure SplitString:
Parameters:
S: String to split
separator: character to use as separator between substrings
substrings: list to take the substrings
Description: Isolates the individual substrings and copies them into the passed stringlist. Note that we only add to the list, we do not clear it first! If two separators follow each other directly an empty string will be added to the list.
Error Conditions: will do nothing if the stringlist is not assigned
Created: 08.07.97 by P. Below
}

procedure SplitString(const S: string; separator: Char; substrings: TStringList);
var
  i, n: Integer;
begin
  if Assigned(substrings) and (Length(S) > 0) then
  begin
    i := 1;
    repeat
      n := IScan(separator, S, i);
      if n = 0 then
        n := Length(S) + 1;
      substrings.Add(Copy(S, i, n - i));
      i := n + 1;
    until
      i > Length(S);
  end;
end;

resourcestring

  eInvalidViewstyle = '%s: the listview %s is not in vsReport mode.';

  {
  Procedure SaveListviewStrings:
  Parameters :
  listview : listview to save, must be in vsreport mode, <> nil
  filename : full pathname of file to create
  Description:
  Iterates over the items of the passed listview and saves the item and
        subitem strings to file. The created file is a plain text file, each item
        occupies one line, subitems are separated by tab characters.
  Error Conditions:
  An exception will be raised if the listview is not in vsreport mode or if the
        file cannot be written to.
  Created: 2.4.2000 by P. Below
  }

procedure SaveListviewStrings(listview: TLIstview; const filename: string);
var
  sl: TStringlist;
  S: string;
  i, k: Integer;
  item: TLIstItem;
begin
  Assert(Assigned(listview));
  if listview.ViewStyle <> vsReport then
    raise Exception.CreateFmt(eInvalidViewstyle, ['SaveListviewStrings',
      listview.name]);
  sl := TStringlist.Create;
  try
    for i := 0 to listview.items.count - 1 do
    begin
      item := listview.Items[i];
      S := item.Caption;
      for k := 0 to item.SubItems.Count - 1 do
        S := S + #9 + item.Subitems[k];
      sl.Add(S);
    end;
    sl.SaveToFile(filename);
  finally
    sl.free
  end;
end;

{
Procedure LoadListviewStrings:
Parameters :
listview : listview to load, must be in vsreport mode, <> nil
filename : full pathname of file to read
Description:
Reads the file into a stringlist and then dissects each line into another list
of strings. It expects the lists elements to be separated by tab characters. For
each line read a new listitem is added to the listview and its caption and subitems are set from the lines elements. Note that the listview is not cleared
first, so the new items will be added to whatever items the listview already contains.
Error Conditions:
An exception will be raised if the listview is not in vsreport mode or if the file cannot be loaded.
Created: 2.4.2000 by P. Below
}

procedure LoadListviewStrings(listview: TLIstview; const filename: string);
var
  sl, lineelements: TStringlist;
  i: Integer;
  item: TLIstItem;
begin
  Assert(Assigned(listview));
  if listview.ViewStyle <> vsReport then
    raise Exception.CreateFmt(eInvalidViewstyle, ['LoadListviewStrings',
      listview.name]);
  sl := TStringlist.Create;
  try
    sl.LoadFromFile(filename);
    lineelements := Tstringlist.Create;
    try
      for i := 0 to sl.count - 1 do
      begin
        lineelements.Clear;
        SplitString(sl[i], #9, lineelements);
        if lineelements.Count > 0 then
        begin
          item := listview.Items.Add;
          item.Caption := lineelements[0];
          lineelements.Delete(0);
          item.SubItems.Assign(lineelements);
        end;
      end;
    finally
      lineelements.free;
    end;
  finally
    sl.free
  end;
end;

const
  testfilename = 'c:\temp\testfile.txt';

procedure TForm1.ClearButtonClick(Sender: TObject);
begin
  listview1.items.clear;
end;

procedure TForm1.SaveButtonClick(Sender: TObject);
begin
  SaveListviewStrings(listview1, testfilename);
end;

procedure TForm1.LoadButtonClick(Sender: TObject);
begin
  LoadListviewStrings(listview1, testfilename);
end;

end.


Solve 2:

Subclass TListView and add these to your new component:

unit MyListView;

interface

uses
  SysUtils, Classes, ComCtrls, Forms, Windows, Menus, Controls;

type

  TCheckBoxString = class(TComponent)
  private
    FTheString: string;
  protected
  public
  published
    property CheckBoxString: string read FTheString write FTheString;
  end;

  TMyListView = class(TListView)
  private
  public
    procedure SaveToFile(FileName: string);
    procedure LoadFromFile(FileName: string);
  published
  end;

procedure Register;

implementation

procedure TMyListView.SaveToFile(FileName: string);
var
  FStream: TMemoryStream;
  i: Integer;
  FStrings: TCheckBoxString;
begin
  FStream := TMemoryStream.Create;
  FStrings := TCheckBoxString.Create(nil);
  try
    FStream.WriteComponent(Self);
    if Self.Checkboxes then
    begin
      FStrings.CheckBoxString := '';
      for i := 0 to Self.Items.Count - 1 do
      begin
        if Self.Items[i].Checked then
          FStrings.CheckBoxString := FStrings.CheckBoxString + 'T'
        else
          FStrings.CheckBoxString := FStrings.CheckBoxString + 'F';
      end;
      FStream.WriteComponent(FStrings);
    end;
    FStream.SaveToFile(FileName);
  finally
    FStream.Free;
    FStrings.Free;
  end;
end;

procedure TMyListView.LoadFromFile(FileName: string);
var
  FStream: TFileStream;
  i: Integer;
  FStrings: TCheckBoxString;
begin
  FStream := TFileStream.Create(FileName, fmOpenRead);
  FStrings := TCheckBoxString.Create(nil);
  try
    Self.Columns.BeginUpdate;
    Self.Items.BeginUpdate;
    Self.Items.Clear;
    Self := FStream.ReadComponent(Self) as TMyListView;
    if Self.Checkboxes then
    begin
      FStrings := FStream.ReadComponent(FStrings) as TCheckBoxString;
      for i := 0 to Self.Items.Count - 1 do
      begin
        if (i + 1) <= Length(FStrings.CheckBoxString) then
          Self.Items[i].Checked := (FStrings.CheckBoxString[i + 1] = 'T');
      end;
    end;
  finally
    FStream.Free;
    FStrings.Free;
    Self.Columns.EndUpdate;
    Self.Items.EndUpdate;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése