Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   FreePascal Listview speichern und laden (https://www.delphipraxis.net/182453-listview-speichern-und-laden.html)

LordGinn 25. Okt 2014 22:21

Listview speichern und laden
 
Hallo.

Ich möchte 12 Listviewen speichern und laden.
Wie kann ich das schaffen?
Die einfache Variante mit Savedialoge.execute funktioniert nicht und PosEx kennt mein Lazarus v.1.2.4 nicht.
Ich habe auch versucht aus anderen Forenbeiträgen schlau zu werden, aber leider erfolglos.

Crosspost http://www.entwickler-ecke.de/viewto...&postorder=asc

Helmi 25. Okt 2014 22:24

AW: Listview speichern und laden
 
vielleicht funktioniert das hier:

http://www.swissdelphicenter.ch/de/showcode.php?id=729

Sir Rufo 25. Okt 2014 22:29

AW: Listview speichern und laden
 
  • Welche einfache Variante funktioniert denn nur mit
    Delphi-Quellcode:
    TSaveDialog.Execute
    ?
  • Und willst du wirklich die ListViews abspeichern, oder eventuell die Daten?
  • Die ListView zeigt ja nur Text an und somit eine interpretierte Version der Daten oder sollen doch die Daten selber gespeichert werden?
  • In welchem Format möchtest du denn speichern? Soll das ein human readable sein (XML, JSON, ...) oder ...
Und wenn du das hier umgesetzt hättest, dann wäre es dir jetzt schnurzpiepe ob es sich um ListViews, ComboBoxen, Memos, TreeViews, Edits, etc. handeln würde. Aber da nicht, fragst du heute nach ListView speichern, morgen nach TreeView speichern usw.

Du kannst ruhig fragen, aber du würdest dir dein Programmiererleben erleichtern, wenn du Daten, Logik und Anzeige trennst.

LordGinn 26. Okt 2014 09:10

AW: Listview speichern und laden
 
Das Trennen von Daten, Logik und Anzeige finde ich richtig, doch bin ich nicht durch deinen Code gestiegen.
Vieles davon habe ich nachgelesen, doch war danach auch nicht schlauer und wusste auch nicht wie ich deinen Code meinem Programm anpasse.

Das hört sich sehr stark nach Sarkasmus an, ob ich die Listview oder die Daten speichern möchte.
Interpretierte Daten? Das versteh ich leider nicht.

Das gespeicherte Format ist mir egal. Für die späteren Anwender wäre ein menschliches lesbares Format sinnvoll.

Außerdem möchte ich alle 12 Listviewen oder Daten in einer Datei speichern.

Sir Rufo 26. Okt 2014 09:47

AW: Listview speichern und laden
 
Es ist definitiv kein Sarkasmus (sonst hättest du den :mrgreen: gesehen, ich bin da sehr pingelig).

Da du nicht verraten hast, was denn da wirklich in den ListVies drin steht, muss ich irgendwie alles annehmen. So z.B.:
NameAlter
Peter Lustig24
Diese Interpretation erfolgt aus den Daten
NameVornameGeburtsdatum
LustigPeter17.03.1990
Du hast jetzt im Prinzip 3 Möglichkeiten die ListView zu speichern:
  • Als Bild (Screenshot der ListView)
  • Die angezeigten (interpretierten) Werte in der ListeView
  • Die zugrundeliegenden Daten
Überlege dir, womit du am meisten anfangen könntest. Alleine das Datum sagt nichts aus, aber im Zusammenhang mit der Information Geburtstag (Kontext) bekommt es eine aussagekräftige Bedeutung.

Darüber hast du dir eben keine Gedanken gemacht. Wenn ich also darauf hinweise, wie kommst du da auf Sarkasmus?

DeddyH 26. Okt 2014 10:50

AW: Listview speichern und laden
 
:thumb:, schön ausgedrückt.

hathor 26. Okt 2014 12:04

AW: Listview speichern und laden
 
Ich weiss nicht, was in FREEPASCAL vorhanden ist (ComCtrls, Types, StrUtils) -
in DELPHI XE2 funktioniert es so:

Delphi-Quellcode:
uses ..., Vcl.ComCtrls, System.Types, System.StrUtils;

procedure ListViewSaveToFile(ListView: TListView; const FileName: string);

  procedure AddTextToLine(var Line: string; const Text: string);
  begin
    Line := Line + Text + #9;
  end;

  procedure MoveCompletedLineToList(const Strings: TStringList; var Line: string);
  begin
    Strings.Add(System.Copy(Line, 1, Length(Line)-1)); //remove trailing tab
    Line := '';
  end;

var
  Strings: TStringList;
  LatestLine: string;
  i, j: Integer;

begin
  LatestLine := '';

  Strings := TStringList.Create;
  try
    for i := 0 to ListView.Items.Count-1 do begin
      AddTextToLine(LatestLine, ListView.Items[i].Caption);
      for j := 0 to ListView.Items[i].SubItems.Count-1 do begin
        AddTextToLine(LatestLine, ListView.Items[i].SubItems[j]);
      end;
      MoveCompletedLineToList(Strings, LatestLine);
    end;
    Strings.SaveToFile(FileName, TEncoding.UTF8);
  finally
    Strings.Free;
  end;
end;

procedure ListViewLoadFromFile(ListView: TListView; const FileName: string);
var
  Strings: TStringList;
  i, j: Integer;
  Fields: TStringDynArray;
  Item: TListItem;
begin
  Strings := TStringList.Create;
  try
    Strings.LoadFromFile(FileName);
    ListView.Clear;
    for i := 0 to Strings.Count-1 do begin
      Fields := SplitString(Strings[i], #9);
      Item := ListView.Items.Add;
      Item.Caption := Fields[0];
      for j := 1 to high(Fields) do begin
        Item.SubItems.Add(Fields[j]);
      end;
    end;
  finally
    Strings.Free;
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
ListViewSaveToFile(ListView1,'D:\LV1.txt');
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
ListViewLoadFromFile(ListView1,'D:\LV1.txt');
end;

LordGinn 26. Okt 2014 14:25

AW: Listview speichern und laden
 
@Sir Rufo

Screenshot bringt mir nichts, da ich die Listviewen mit der gespeicherten Datei wieder füllen möchte.
Danke für das Beispiel. Interpretierte Daten gibt es bei mir nicht.
Listviewen sehen zb so aus:
Filme // verliehen an // für diesen Zeitraum
Ich habe mir Gedanken gemacht. Ich muss nur lernen, die richtigen Worte zu wählen und mich exakt auszudrücken damit Programmierer mich verstehen.
In der gespeicherten Datei muss der Kontext nicht berücksichtigt werden, wer dahinter steigt kann sich freuen und eventuell in der gespeicherten Datei etwas verändern und die anderen laden die Datei durch das Programm und sehen wieder alles in den Listviewen.

@hathor

Danke für den Code. Ich werde ihn bei Gelegenheit testen.

@Sir Rufo

Wie bei hathor am Ende nur mit savedialog.execute hatte ich im Internet gefunden, aber ohne das ganze vorangestellte und da dachte ich, das wäre dann integriert.
Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
begin
ListViewSaveToFile(ListView1,'D:\LV1.txt');
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
ListViewLoadFromFile(ListView1,'D:\LV1.txt');
end;

Dejan Vu 27. Okt 2014 07:56

AW: Listview speichern und laden
 
Zitat:

Zitat von LordGinn (Beitrag 1277449)
Ich muss nur lernen, die richtigen Worte zu wählen und mich exakt auszudrücken damit Programmierer mich verstehen.

Programmierer lieben es, Dinge wörtlich zu nehmen, denn dann können Sie mal wieder zeigen, wie überlogisch sie denken. :mrgreen:

LordGinn 27. Okt 2014 10:03

AW: Listview speichern und laden
 
@ hathor
Zitat:

Delphi-Quellcode:
uses ..., Vcl.ComCtrls, System.Types, System.StrUtils;

Zitat:

Delphi-Quellcode:
Strings.SaveToFile(FileName, TEncoding.UTF8);

Das nimmt er bei mir nur ohne Vcl. bzw. System. und dann kann er mit TEncoding.UTF8 nichts anfangen.

himitsu 27. Okt 2014 10:08

AW: Listview speichern und laden
 
In "Delphi" haben inzwischen viele Units einen Namespace. (das z.B. das "Vcl." für Units der VCL)
Und das mit dem Encoding ist ebenfalls eine Delphi-Sache (seit Delphi 2009) ... da kann es sein, daß es im Lazarus/FreePascal anders gelöst ist, bzw. etwas anders heißt oder sich in anderen Units befindet.

LordGinn 27. Okt 2014 11:07

AW: Listview speichern und laden
 
Ich hatte anscheinend nur vergessen etwas bei uses zu ergänzen.
http://www.delphipraxis.net/17863-li...eichern-2.html

Jetzt funktioniert es mit den Daten aus einer Listview. Ich versuche erst mal selbst herauszufinden wie man alle Daten aus den 12 Listviewen in einer Datei speichern kann und würde mich dann bei (nicht) Erfolg melden.

JamesTKirk 27. Okt 2014 11:46

AW: Listview speichern und laden
 
Zitat:

Zitat von himitsu (Beitrag 1277484)
In "Delphi" haben inzwischen viele Units einen Namespace. (das z.B. das "Vcl." für Units der VCL)
Und das mit dem Encoding ist ebenfalls eine Delphi-Sache (seit Delphi 2009) ... da kann es sein, daß es im Lazarus/FreePascal anders gelöst ist, bzw. etwas anders heißt oder sich in anderen Units befindet.

LordGinn verwendet wahrscheinlich ein Lazarus mit FPC 2.6.4, welcher im Gegensatz zur aktuellen Entwicklungsversion 2.7.1 weder Namespaces noch TEncoding unterstützt (wobei erstere sich in FPC auch noch nicht angefangen haben durchzusetzen, da eben das aktuelle Release sie noch nicht unterstützt).

@LordGinn: das Weglassen von
Delphi-Quellcode:
Vcl.
bzw.
Delphi-Quellcode:
System.
ist in diesem Fall also richtig.

Gruß,
Sven

hathor 27. Okt 2014 13:20

AW: Listview speichern und laden
 
Zitat:

Zitat von hathor (Beitrag 1277442)
Ich weiss nicht, was in FREEPASCAL vorhanden ist (ComCtrls, Types, StrUtils) -
in DELPHI XE2 funktioniert es so:
...

Lesen muss man können...

LordGinn 27. Okt 2014 21:41

AW: Listview speichern und laden
 
Ich benutze jetzt diesen Code.
http://www.delphipraxis.net/128391-post11.html

Ich habe ein bisschen probiert und versucht Listview2 mit einzubeziehen, mittels einem weiteren Delimitter und dann noch einem Trenner zwischen Listview1 und Listview2.
Bis jetzt ist es nur raten, da mir viele Begriffe in dem Code nicht bekannt sind.

Weiß jemand, wie man das jetzt angehen kann?
Meine Logik wäre folgende:
Wie in dem verlinkten Code, nur dass er aufhört Listview1 zu füllen wenn er das besondere Trennzeichen findet.
Dann würde ich denselben Code auch für Listview2 nehmen mit demselben Delimiter, nur dass er erst nach dem besonderen Trennzeichen anfängt.
Jedes Trennzeichen zwischen den Listviewen ist ein unikat.

LordGinn 2. Nov 2014 10:38

AW: Listview speichern und laden
 
Hier der Zwischenstand.


Das Speichern funktioniert.
Delphi-Quellcode:
procedure TForm1.Button13Click(Sender: TObject);
Var
  SaveList: TStrings;
  i, j: Integer;
  TempStr: String;
Const
  ItemTrenner = #134;
  ListTrenner1 = #179;
  ListTrenner2 = #178;

Begin
  If Not SaveDialog1.Execute Then Exit;
  SaveList := TStringList.create;
  Try
    With ListView1 Do
    Begin
      For i := 0 To pred(Items.Count) Do
      Begin
        TempStr := '';
        With Items[i] Do
          For j := 0 To pred(SubItems.Count) Do
            TempStr := TempStr + ItemTrenner + SubItems[j];

        SaveList.Add(Items[i].Caption + TempStr);


      End;

end;
    SaveList.add(Listtrenner1);

    With ListView2 Do
      For i := 0 To pred(Items.Count) Do
      Begin
        TempStr := '';
        With Items[i] Do
          For j := 0 To pred(SubItems.Count) Do
            TempStr := TempStr + ItemTrenner + SubItems[j];

        SaveList.Add(Items[i].Caption + TempStr);


      End;

end;

    SaveList.add(Listtrenner2);

    SaveList.SaveToFile(SaveDialog1.FileName+'.txt');

  Finally
    FreeAndNil(SaveList);
  End;
End;
Das Laden funktioniert nicht. Es kommt keine Fehlermeldung. Die Listviewen bleiben leer. Wird bestimmt ein Fehler beim Copy sein.
Delphi-Quellcode:
procedure TForm1.Button12Click(Sender: TObject);
Var
  LoadList, ErsteLW, ZweiteLW: TStrings;
  i, ActPos, PrevPos: Integer;
Const
  ItemTrenner = #134;
  ListTrenner1 = #179;
  ListTrenner2 = #178;

Begin
  If Not OpenDialog1.Execute Then Exit;
  LoadList := TStringList.create;
  ErsteLW:=TStringList.create;
  ZweiteLW:=TStringList.create;

  Try
    LoadList.LoadFromFile(OpenDialog1.FileName);
    ListView1.Items.Clear;
    Listview2.items.clear;



    For i := 0 To pred(LoadList.Count) Do
    Begin
    ErsteLW.add(Copy(LoadList[i], 1, Pos (ListTrenner1, Loadlist[i]) - 1));
    ZweiteLW.add(Copy(LoadList[i], Pos (ListTrenner1, Loadlist[i]) + 1, Pos (ListTrenner2, Loadlist[i]) -1));
    end;

    For i := 0 To pred(ErsteLW.Count) Do
    Begin
      PrevPos := 1;
      ActPos := 1;
      ActPos := PosEx(ItemTrenner, ErsteLW[i], succ(ActPos));
      With ListView1.Items.Add Do
      Begin
        Caption := Copy(ErsteLW[i], PrevPos, (ActPos - PrevPos));
        PrevPos := succ(ActPos);
        Repeat
          ActPos := PosEx(ItemTrenner, ErsteLW[i], succ(ActPos));
          If ActPos <> 0 Then
            SubItems.Add(Copy(ErsteLW[i], PrevPos, (ActPos - PrevPos)))
          Else
            SubItems.Add(Copy(ErsteLW[i], PrevPos, Length(ErsteLW[i])));
          PrevPos := succ(ActPos);
        Until ActPos = 0;
      End;
    End;

    For i := 0 To pred(ZweiteLW.Count) Do
    Begin
      PrevPos := 1;
      ActPos := 1;
      ActPos := PosEx(ItemTrenner, ZweiteLW[i], succ(ActPos));
      With ListView2.Items.Add Do
      Begin
        Caption := Copy(ZweiteLW[i], PrevPos, (ActPos - PrevPos));
        PrevPos := succ(ActPos);
        Repeat
          ActPos := PosEx(ItemTrenner, ZweiteLW[i], succ(ActPos));
          If ActPos <> 0 Then
            SubItems.Add(Copy(ZweiteLW[i], PrevPos, (ActPos - PrevPos)))
          Else
            SubItems.Add(Copy(ZweiteLW[i], PrevPos, Length(ZweiteLW[i])));
          PrevPos := succ(ActPos);
        Until ActPos = 0;
      End;
    End;

  Finally
    FreeAndNil(LoadList);
    FreeAndNil(ErsteLW);
    FreeAndNil(ZweiteLW);
  End;
End;

Sir Rufo 2. Nov 2014 11:22

AW: Listview speichern und laden
 
Du solltest dir das Leben erheblich vereinfachen indem du alles in kleine Teile aufteilst.

Hier mal ein Beispiel für deine ListView-Speicher-Problematik (in Delphi könnte in FPC etwas anders sein, das Prinzip ist aber gleich):
Delphi-Quellcode:
unit Form.Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls;

type
  TForm1 = class( TForm )
    ListView1: TListView;
    ListView2: TListView;
    SaveDialog1: TSaveDialog;
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click( Sender: TObject );
    procedure Button2Click( Sender: TObject );
  private
    function Serialize( ListView: TListView ): string; overload;
    function Serialize( ListItems: TListItems ): string; overload;
    function Serialize( ListItem: TListItem ): string; overload;
    procedure Deserialize( const Data: string; ListView: TListView ); overload;
    procedure Deserialize( const Data: string; ListItems: TListItems ); overload;
    procedure Deserialize( const Data: string; ListItem: TListItem ); overload;
    procedure SaveToFile( const AFileName: string );
    procedure LoadFromFile( const AFileName: string );
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
{ TForm1 }

procedure TForm1.Button2Click( Sender: TObject );
begin
  if SaveDialog1.Execute
  then
    SaveToFile( SaveDialog1.FileName );
end;

procedure TForm1.SaveToFile( const AFileName: string );
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.Values['ListView1'] := Serialize( ListView1 );
    LStrings.Values['ListView2'] := Serialize( ListView2 );
    LStrings.SaveToFile( AFileName );
  finally
    LStrings.Free;
  end;
end;

function TForm1.Serialize( ListView: TListView ): string;
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.Values['Items'] := Serialize( ListView.Items );
    Result := LStrings.DelimitedText;
  finally
    LStrings.Free;
  end;
end;

function TForm1.Serialize( ListItems: TListItems ): string;
var
  LIdx: Integer;
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    for LIdx := 0 to ListItems.Count - 1 do
      LStrings.Add( Serialize( ListItems[LIdx] ) );
    Result := LStrings.DelimitedText;
  finally
    LStrings.Free;
  end;
end;

function TForm1.Serialize( ListItem: TListItem ): string;
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.Values['Caption'] := ListItem.Caption;
    LStrings.Values['SubItems'] := ListItem.SubItems.DelimitedText;
    Result := LStrings.DelimitedText;
  finally
    LStrings.Free;
  end;
end;

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

procedure TForm1.LoadFromFile( const AFileName: string );
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.LoadFromFile( AFileName );
    Deserialize( LStrings.Values['ListView1'], ListView1 );
    Deserialize( LStrings.Values['ListView2'], ListView2 );
  finally
    LStrings.Free;
  end;
end;

procedure TForm1.Deserialize( const Data: string; ListView: TListView );
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.DelimitedText := Data;
    Deserialize( LStrings.Values['Items'], ListView.Items );
  finally
    LStrings.Free;
  end;
end;

procedure TForm1.Deserialize( const Data: string; ListItems: TListItems );
var
  LIdx: Integer;
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.DelimitedText := Data;
    ListItems.Clear;
    for LIdx := 0 to LStrings.Count - 1 do
      Deserialize( LStrings[LIdx], ListItems.Add );
  finally
    LStrings.Free;
  end;
end;

procedure TForm1.Deserialize( const Data: string; ListItem: TListItem );
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.DelimitedText := Data;
    ListItem.Caption := LStrings.Values['Caption'];
    ListItem.SubItems.DelimitedText := LStrings.Values['SubItems'];
  finally
    LStrings.Free;
  end;
end;

end.
Alles nur kleine Methoden ... hübsch, gell?

UPDATE Kleine Verbesserung für zuküntige Erweiterung

smmahaup 19. Okt 2016 09:52

AW: Listview speichern und laden
 
@Sir Rufo
Hallo Rufo,
Schöner Code! Funktioniert bestens!
wäre es ok wenn ich deinen Code für meine Bachelorarbeit in etwas überarbeiteten Form verwenden dürfte?
Natürlich wirst du als Urheber des Codes angegeben.
PS: Ich frage nur hier, da ich dir leider keine PN schreiben kann!
mfg Markus


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:37 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz