Avatar billede megabyte_ Nybegynder
29. maj 2008 - 13:16 Der er 18 kommentarer og
1 løsning

xml treevire og listview

Hej

Jeg er løbet ind i et problem, jeg bruger delphi 7 personal og har brug for at gemme og hente data fra en xml fil til et treeview og et list view

min ide var at lave en xml fil ca sådan her
<data>
<treeview>
  <item1></item1>
  <data1></data1>
  <data2></data2>
  <data3></data4>
  <item2></item1>
  <data1></data1>
  <data2></data2>
  <data3></data4>
</treeview>
<listview>
  <item1></item1>
  <data1></data1>
  <data2></data2>
  <data3></data4>
  <data4></data4>
</listview>
</data>

I kan se idéen selv om den ikke er bygget rigtigt op :)

Treeview struktur
Item1
    Data
    Data
    Data
Item2
    Data
    Data
    Data

Listview

Item1    data1    data2    data3    data4
Item2    data1    data2    data3    data4

De data der er I listview og treeview er ikke de same

Håber der er nogen der kan hjælpe
Jeg har set lidt på msxml og openxml, håber på at der kan findes en løsning uden brug af komponenter

/MB
Avatar billede hrc Mester
29. maj 2008 - 13:47 #1
Har du en schema-fil? Med den kan du generere en unit der håndterer ovenstående data som arrays du bare skal pløje igennem. Den kan du eventuelt nedarve til en klasse der ordner putter <itemX>-nodes i hver sin liste. Ikke noget med besværlige traverseringer af en dum XML-struktur.
Avatar billede megabyte_ Nybegynder
29. maj 2008 - 14:26 #2
Hej

schema-fil? det må du lige uddybe lidt, jeg har været væk fra programering alt for længe :)
Avatar billede megabyte_ Nybegynder
29. maj 2008 - 14:28 #3
Andre måder at gemme data'en på kan også bruges, nu faldt jeg bare lige over XML og det lød som en god ide.

Der er endnu ikke lavet nogen datafil da daten først kommer fra programmet :)
Avatar billede js_delphi Nybegynder
29. maj 2008 - 21:03 #4
Er det udelukket at hente dataene fra XML filen node for node, og overfoere dem til det respektive view?

Noget med:
ListViewEtEllerAndet := XMLDoc.ChildNodes['Data'].ChildNodes['listview'].ChildNodes[item1].NodeValue);

Alt sammen med IXMLDocument.

Ps.: jeg kender intet til ListView.
Avatar billede kroning Nybegynder
29. maj 2008 - 22:56 #5
Hvis det ikke behøver at gemmes/hentes til samme fil kan du gøre sådan:

TreeView:
TreeView1.SaveToFile('filnavn.txt'); // gemmer
TreeView1.LoadFromFile('filnavn.txt'); // henter

ListView:
http://www.eksperten.dk/spm/786375?Esession=
Se klokken: 16:21:28
Avatar billede megabyte_ Nybegynder
30. maj 2008 - 08:34 #6
Det skal være til samme film
Og det er både læse og gemme data
Avatar billede hrc Mester
30. maj 2008 - 10:19 #7
Hvis XML ikke er et krav så stream' data i stedet. Det er meget lettere (og hurtigere). Har flere gange skrevet indlæg hvor jeg bruger TReader og TWriter til at gemme den slags data.

http://www.eksperten.dk/spm/828561
Avatar billede js_delphi Nybegynder
31. maj 2008 - 15:42 #8
Forstod du egentlig min ide?
Eksemplet var hvordan data kan hentes fra XML filen.
At skrive og gemme en XML fil er stort set ligesaa enkelt.
Avatar billede hrc Mester
01. juni 2008 - 22:49 #9
Hvis data kommer fra programmet og andre programmer ikke skal drage umiddelbar nytte deraf, så er XML overkill. Streaming er vejen frem; hvorfor ikke gøre som alle andre programmer? Fordelen ved at streame manuelt i forhold til den indbyggede (SaveToFile et al) er, at du har fuld styr over processen og over hvad der gemmes. Når først klasserne er på plads kan du tilføje, tilrette og gøre ved. Desuden kan du med en simpel versionsstyring gøre filerne bagudkompatibele, dvs. du kan stadig læse en datafil fra program v. 1.0 i program v. 12.01b
Avatar billede megabyte_ Nybegynder
02. juni 2008 - 09:11 #10
hrc, din løsning lyder som en god ide
Jeg har set på det og har fået lært et par ting
Hvad jeg har gjort pt er at lave et par record, som jeg stremer til og fra en TMemoryStream som gemmes til en fil

Men hvordan får jeg styr på om det er en listview eller en treeview record, jeg har lavet 2 records en til hver, men hvordan kan jeg gemme dem i samme fil ?

PDataList= ^TDataList;
TDataList= Record
  data1      : string[15];
  data2 : integer;

PDataTree= ^TDataTree;
TDataTRee= Record
  data1      : string[10];
  data2 : integer;
  data3 : integer;

Har du evt nogle kilder med mere info om dette

/MB
Avatar billede hrc Mester
02. juni 2008 - 13:05 #11
Jeg bryder mig ikke om at bruge records længere. Da klasser kom til synes jeg de blev forældede. De er hurtigere men i nedenstående bruger jeg den skjulte "string"-klasse som ikke er bundet til max. 255 karakterer.

Jeg ville nok ende med et klasseorgie ... som nedenstående. Det er måske skudt over målet, har end ikke tjekket eksemplet i det link jeg lagde. Det var bare en idé der udviklede sig. Jeg har to baseklasser hvori jeg definerer nogle fælles metoder og fra disse nedarver jeg resten. Der er en klasse til et TTreeView og et TTListView. Hvis du vil have dem samlet laver du bare en klasse:

TMyData = class
private
  fListViewList: TListViewList;
  fTreeViewList: TTreeViewList;
public
  constructor Create; // Opretter klasserne her
  destructor Destroy; override; // Sletter dem her
end;

... Nok om det. Her er unitten

unit UData;

interface

uses
  SysUtils, Classes, ComCtrls, ContNrs;

type
  TBaseData = class
  private
  public
    procedure SaveToWriter(aWriter: TWriter); virtual; abstract;
    procedure LoadFromReader(aReader: TReader); virtual; abstract;
  end;

  TBaseList = class(TObjectList)
  private
  public
    procedure SaveToStream(aStream: TStream); virtual;
    procedure SaveToFile(const aFilename: string); virtual;
    procedure LoadFromStream(aStream: TStream); virtual; abstract;
    procedure LoadFromFile(const aFilename: string); virtual;
  end;

  TTreeViewData = class(TBaseData)
  private
    fName: string;
    fValue2: integer;
    fValue1: integer;
  public
    constructor Create(const aName: string; const aValue1, aValue2: integer); overload;
    constructor Create(aReader: TReader); overload;
    property Name: string read fName;
    property Value1: integer read fValue1 write fValue1;
    property Value2: integer read fValue2 write fValue2;
    procedure FillTreeNode(aTreeNode: TTreeNode);
    procedure SaveToWriter(aWriter: TWriter); override;
    procedure LoadFromReader(aReader: TReader); override;
  end;

  TListViewData = class(TBaseData)
  private
    fName: string;
    fValue: integer;
  public
    constructor Create(const aName: string; const aValue: integer); overload;
    constructor Create(aReader: TReader); overload;
    property Name: string read fName;
    property Value: integer read fValue write fValue;
    procedure FillListItem(aListItem: TListItem);
    procedure SaveToWriter(aWriter: TWriter); override;
    procedure LoadFromReader(aReader: TReader); override;
  end;

  TListViewList = class(TBaseList)
  private
    function GetListViewData(const aIndex: integer): TListViewData;
  public
    property Items[const aIndex: integer]: TListViewData read GetListViewData; default;
    procedure LoadFromStream(aStream: TStream); override;
    procedure FillListView(aListView: TListView);
  end;

  TTreeVievList = class(TBaseList)
  private
    function GetTreeViewData(const aIndex: integer): TTreeViewData;
  public
    property Items[const aIndex: integer]: TTreeViewData read GetTreeViewData; default;
    procedure LoadFromStream(aStream: TStream); override;
    procedure FillTreeView(aTreeView: TTreeView);
  end;

implementation

{ TTreeViewData }

constructor TTreeViewData.Create(const aName: string; const aValue1, aValue2: integer);
begin
  inherited Create;
  fName := trim(aName);
  fValue1 := aValue1;
  fValue2 := aValue2;
end;

constructor TTreeViewData.Create(aReader: TReader);
begin
  inherited Create;
  LoadFromReader(aReader);
end;

procedure TTreeViewData.FillTreeNode(aTreeNode: TTreeNode);
begin
  aTreeNode.DeleteChildren;
  aTreeNode.Data := self;
  aTreeNode.Text := fName;
  (aTreeNode.TreeView as TTreeView).Items.AddChild(aTreeNode,IntToStr(fValue1));
  (aTreeNode.TreeView as TTreeView).Items.AddChild(aTreeNode,IntToStr(fValue2));
end;

procedure TTreeViewData.LoadFromReader(aReader: TReader);
begin
  fName := aReader.ReadString;
  fValue1 := aReader.ReadInteger;
  fValue2 := aReader.ReadInteger;
end;

procedure TTreeViewData.SaveToWriter(aWriter: TWriter);
begin
  aWriter.WriteString(fName);
  aWriter.WriteInteger(fValue1);
  aWriter.WriteInteger(fValue2);
end;


{ TListViewData }

constructor TListViewData.Create(const aName: string; const aValue: integer);
begin
  inherited Create;
  fName := trim(aName);
  fValue := aValue;
end;

constructor TListViewData.Create(aReader: TReader);
begin
  inherited Create;
  LoadFromReader(aReader);
end;

procedure TListViewData.FillListItem(aListItem: TListItem);
begin
  aListItem.SubItems.Clear;
  aListItem.Data := self;
  aListItem.Caption := fName;
  aListItem.SubItems.Add(IntToStr(fValue));
end;

procedure TListViewData.LoadFromReader(aReader: TReader);
begin
  fName := aReader.ReadString;
  fValue := aReader.ReadInteger;
end;

procedure TListViewData.SaveToWriter(aWriter: TWriter);
begin
  aWriter.WriteString(fName);
  aWriter.WriteInteger(fValue);
end;

{ TMyList }

procedure TListViewList.FillListView(aListView: TListView);
var
  i: integer;
begin
  aListView.Items.BeginUpdate;
  try
    aListView.Items.Clear;
    for i := 0 to Count - 1 do
      Items[i].FillListItem(aListView.Items.Add);
  finally
    aListView.Items.EndUpdate;
  end;
end;

function TListViewList.GetListViewData(const aIndex: integer): TListViewData;
begin
  result := inherited Items[aIndex] as TListViewData;
end;

procedure TListViewList.LoadFromStream(aStream: TStream);
var
  i: integer;
  Reader: TReader;
begin
  Reader := TReader.Create(aStream,1024);
  try
    for i := 0 to Reader.ReadInteger - 1 do
      Add(TListViewData.Create(Reader));
  finally
    Reader.Free;
  end;
end;

{ TTreeVievList }

procedure TTreeVievList.FillTreeView(aTreeView: TTreeView);
var
  i: integer;
begin
  aTreeView.Items.BeginUpdate;
  try
    aTreeView.Items.Clear;
    for i := 0 to Count - 1 do
      Items[i].FillTreeNode(aTreeView.Items.Add(nil,''));
  finally
    aTreeView.Items.EndUpdate;
  end;
end;

function TTreeVievList.GetTreeViewData(const aIndex: integer): TTreeViewData;
begin
  result := inherited Items[aIndex] as TTreeViewData;
end;

procedure TTreeVievList.LoadFromStream(aStream: TStream);
var
  i: integer;
  Reader: TReader;
begin
  Reader := TReader.Create(aStream,1024);
  try
    for i := 0 to Reader.ReadInteger - 1 do
      Add(TTreeViewData.Create(Reader));
  finally
    Reader.Free;
  end;
end;

{ TBaseList }

procedure TBaseList.LoadFromFile(const aFilename: string);
var
  FileStream: TFileStream;
begin
  FileStream := TFileStream.Create(aFilename,fmOpenRead);
  try
    LoadFromStream(FileStream);
  finally
    FileStream.Free;
  end;
end;

procedure TBaseList.SaveToFile(const aFilename: string);
var
  FileStream: TFileStream;
begin
  FileStream := TFileStream.Create(aFilename,fmCreate);
  try
    SaveToStream(FileStream);
  finally
    FileStream.Free;
  end;
end;

procedure TBaseList.SaveToStream(aStream: TStream);
var
  i: integer;
  Writer: TWriter;
begin
  Writer := TWriter.Create(aStream,1024);
  try
    Writer.WriteInteger(Count);
    for i := 0 to Count - 1 do
      (Items[i] as TBaseData).SaveToWriter(Writer);
    Writer.FlushBuffer;
  finally
    Writer.Free;
  end;
end;

end.
Avatar billede hrc Mester
02. juni 2008 - 13:11 #12
Jeg ved godt det fylder en del, men der bruges nogle objektorienterede teknikker som jeg håber andre vil synes lærerige. Bruger bl.a. abstrakte metoder. Kunne overveje at lave det med Interfaces i stedet men jeg synes de er besværligere.

Selvom dit oplæg ikke vil fylde helt så meget er det min påstand, at der vil være større muligheder for at noget fejler.

Kunne overveje at lave ovenstående som en nedarving af TCollectionData og TCollectionItems men jeg kan godt lide TObjectLists simplicitet.
Avatar billede megabyte_ Nybegynder
02. juni 2008 - 14:43 #13
Det er noget af en omgang, men det ser meget spændene ud, jeg har aldrig arbejdet med klasser før så det er helt nyt for mig

Hvis du ligger inde med noget godt materiale om det må du gerneposte det her

/MB
Avatar billede megabyte_ Nybegynder
02. juni 2008 - 15:25 #14
Hej

Jeg har set lidt på det, og er kommet til at se et problem som jeg også vil få med records.
Problemet er at data til treeview kan have 0 – xxx subnotes, hvordan vil man lettest overkomme dette?
Man kan slf lave et objekt pr subnote og soter dem når man indsætter dem i treeview, men dette vil være langsomt og ikke særlig smart

/MB
Avatar billede hrc Mester
02. juni 2008 - 23:05 #15
Enten kan du erstatte Value1 og Value2 med en TStringList. Så er træets niveau 0 og 1 på plads. Skal du have flere niveauer kan du lade data-klassen være en liste som kan indeholde et vilkårligt antal niveauer og items. Måske skulle data-klasserne bare nedarve fra TTreeNode?

Nedarvet fra TObjectList ser det sådan ud:

TBaseData = class(TObjectList)
private
  fName: string;
public
  constructor Create(const aName: string);
  property Items[const aIndex: integer]: TBaseData read GetBaseData; default;
  ...
end;

TTreeViewData = class(TBaseData)
private
public
end;

...

var
  Index: integer;
  TreeViewData: TTreeViewData;
begin
  TreeViewData := TTreeViewData.Create('Hello world');
  Index := TreeViewData.Add(TTreeViewData.Create('Hi. How are you?');
  TreeViewData[Index].Add(TTreeViewData.Create('Fine thanks'));
  osv.
end;

Man kan i øvrigt skrive ovenstående sådan her, men det er ligesom læsbarheden forsvinder :-):

  TreeViewData := TTreeViewData.Create('Hello world').Add(TTreeViewData.Create('Hi How are you?').Add(TTreeViewData.Create('Fine thanks')));
Avatar billede megabyte_ Nybegynder
11. juni 2008 - 14:25 #16
Lukket
Avatar billede js_delphi Nybegynder
11. juni 2008 - 16:33 #17
Han er en spøjs fætter ham megabyte, hva'
Avatar billede hrc Mester
11. juni 2008 - 20:13 #18
Jeg savner karma-systemet...
Avatar billede megabyte_ Nybegynder
13. juni 2008 - 09:34 #19
Det må i undskylde, jeg var ved og ryde op og fik lukket dette ved en fejl
Jeg har oprettet en ny spm så i kan få jeres point, jeg har brugt hrc's løsning og lært en del af det selv om jeg ikke er helt færdig så ser det godt ud
http://www.eksperten.dk/spm/834756

/MB


/MB
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester