Save and load TListView items to / from a file (Views: 704)
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; |