AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TObjectlist in TObjectList

Ein Thema von mimi · begonnen am 25. Jun 2006 · letzter Beitrag vom 2. Jul 2006
Antwort Antwort
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#1

TObjectlist in TObjectList

  Alt 25. Jun 2006, 16:07
Hallo,
ich habe da ein kleines problemchen:
Delphi-Quellcode:
  TStyle = record
    obj1:TObjectList;
    .....
  end;
und nun habe ich eine weiter tList um das object zu verwalten. das heißt so eine art Object Baum.
Ich möchte gerne folgendes erreichen:
In unser grafik programm "ProGraphic" möchte ich genre noch ein object Kontener einbauen so wie der panel unter delphi d.h. wenn ich mehre objecte verschiebe und die auf ein anderes object verschiebe soll dieses object wo sie drauf geschoeben wurden sind sie besitzt problem:
ich habe eine standart liste da sind alle drin und jetzt hat jedes object ein objl Tobjectliste wo alle objecte reinkommen sollen:
der code sieht so aus:
Delphi-Quellcode:
procedure TForm1.BitBtn1Click(Sender: TObject);
var
  i:Integer;
  s,s1:TStyle;
begin
  // Beim Makierten object die neue liste installisieren
  
  if TFigure(obj.Items[SelObj]).Style.obj1 = nil then begin
    with TFigure(obj.Items[SelObj]).Style do
      obj1:=TObjectList.Create;
  end;
  for i:=obj.count-1 downto 0 do begin
    if (TFigure(obj.Items[i]).Style.isSel = True) and (i <> SelObj) then begin
      if TFigure(obj.Items[i]).Style.obj1 = nil then begin
        s:=TFigure(obj.Items[i]).Style;
        AddObj(s.Typ,TPenTool(s.objTypI),TFigure(obj.Items[i]).Style,TFigure(obj.Items[SelObj]).Style.obj1);
        if TFigure(obj.Items[i]).Style.obj1 <> Nil then begin
          TFigure(obj.Items[i]).Style.obj1.Clear;
          TFigure(obj.Items[i]).Style.obj1.Destroy;
        end;
        obj.OwnsObjects:=True;
        obj.Remove(obj.Items[i]);
        fEigenschaften.clbObjektListe.Items.Delete(i);
      end // if obj1 = nil
      else
        ShowMessage('Objete müssen leer sein,'+#13+' wenn sie verschoben werden sollen');
    end;
  end;

end;
der scheint auch zu funktionieren problem ist nur beim zeichnen muss ich auf eine funktion von TFigure drauzugreifen:
Delphi-Quellcode:
procedure TForm1.DrawBmp; //Markierungsrahmen
var
  i,x: Integer;
  oldColor:TColor;
begin

  Label2.Caption:=IntToStr(t);
  ClearBmp;
  if Obj.Count>0 then begin
    for i:=0 to Obj.Count-1 do begin
      if TFigure(obj.Items[i]).Style.obj1 <> NIL then begin

        for x:=0 to TFigure(obj.Items[i]).Style.obj1.Count-1 do begin
          with TFigure(Obj[i]).Style.obj1 do begin

            TFigure(Items[x]).Draw(bmp);

// DrawStyle(TFigure(TFigure(Obj[i]).Style.obj1.Items[i]));
          end;
        end;
      end
      else begin
        if TFigure(Obj[i]).Style.Visible = True then begin
          TFigure(Obj[i]).Draw(Bmp);
          DrawStyle(TFigure(Obj[i]));
        end; //if visible
      end; // else
    end; // for
  end; // if obj


  PaintBox1.Canvas.Draw(0,0,Bmp);
  StatusBar1.Panels[5].Text:= 'Objekt ' + IntToStr(SelObj+1);
end;
und bei TFigure(Items[x].draw(bmp] kommt eine av und das programm beendet sich... kann mir jemmand sagen warum ?
bzw. eine lösung geben. Währe sehr dankbar....
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#2

Re: TObjectlist in TObjectList

  Alt 2. Jul 2006, 07:47
Hat keiner eine idee wie das gehen könnte ?
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#3

Re: TObjectlist in TObjectList

  Alt 2. Jul 2006, 08:32
HI,
ich hab ehrlich gesagt keine richtige Idee was deine Frage an einigen Stellen betrifft:

Zitat von mimi:
Delphi-Quellcode:
  TStyle = record
    obj1:TObjectList;
    .....
  end;
und nun habe ich eine weiter tList um das object zu verwalten. das heißt so eine art Object Baum.
Eine weitere TList? Wo ist denn die erste TList?
Um das Objekt zu verwalten? Wo ist denn das Objekt? Ein Record ist kein Objekt!

Zitat von mimi:
jetzt hat jedes object ein objl Tobjectliste wo alle objecte reinkommen
Sorry, der Teil ist mir völlig unklar. Was ist denn ein objl Tobjectliste?

An sich würde ich dir hier zu etwas ObjektOrientierung (OO) raten. Für eine solche "Hierachie" und soetwas wie den Bau eines Containers eignet die sich sehr gut. Du kannst einfach eine Basisklasse für alle Grafikobjekte und eine für alle "Container" schaffen. Die Klasse der Container sollte dabei von der Klasse der Grafikobjekte erben. Die hat dann einfach nur die Eigenschaft, zusätztlich Elemente zu Speichern.

Delphi-Quellcode:
type
  TGrafikBasisKlasse = class(TObject)
    private
      FXPosition : Integer;
      FYPosition : Integer;
      ...
    protected
      draw; virtual; abstract;
      setXPosition(const x : Integer);
      setYPosition(const y : Integer);
      ...
    public
      property XPosition : Integer read FXPosition write setXPosition;
      property YPosition : Integer read FYPosition write setYPosition;
      ...
  end;

  TGrafikContainerBasisKlasse = class(TGrafikBasisKlasse)
    private
      FContainedObjects : TObjectList;
    protected
      setXPosition(const x : Integer); override;
      setYPosition(const Y : Integer); override;
      addGraphicObject(const GraphicObject : TGrafikBasisKlasse);
      removeGraphicObject(const GraphicObject : TGrafikBasisKlasse);
    public
  end;
So ganz grob (entschuldige, merke gerade dass meine Variablenbenennung ganz furchtbar ist, durchmischt deutsch/englisch).
Natürlich soll das jeztt keine vollständige Klasse sein, müsstest du entsprechend erweitern. Wichtig ist es die grobe Struktur zu verstehen. Alle Objekte die du verwendest sollten von TGrafikBasisKlasse erben. Sind sie zu dem auch noch ein Container, erben sie entsprechend von TGrafikContainerBasisKlasse (und damit implizit auch von TGrafikBasisKlasse). Also kannst du immer den in ein TGrafikBasisKlasse Objekt casten und die hier vorgegebenen Funktionen nutzen.
Wenn nun setXPosition aufgerufen wird, musst du die x Position deiner Komponente ändern und neu zeichnen. Hierzu kann jede deiner Komponenten (die du ableitest) einfach die draw Methode überschreiben, wo es sich hinzeichnet geht ja aus den gespeicherten Koordinaten hervor.
Hast du einen Container (etwas dass von TGrafikContainerBasisKlasse erbt), so brauchst du hier nicht mehr zu tun, als die Methode, die diesen Container bewegt zu überschreiben. Deine überschriebene Methode ruft dann einfach ihren Vorgänger auf (schließlich muss auch dein Container an der richtigen Stelle gezeichnet werden) und muss danach nur noch alle ELemente bewegen, die in der eigenen Liste drin stehen.

Delphi-Quellcode:
TGrafikContainerBasisKlasse.setXPosition(const x : Integer);
var diffX : Integer;
    i : Integer;
begin
  diffX := x - self.XPosition;
  
  inherited setXPosition(x);
  
  if self.FContainedObjects.Count > 0 then
  begin
    for i := 0 to self.FCountaindedObjects.Count - 1 do
    begin
      // eine Methode move wäre hier sinnvoller als das
      TGrafikBasisKlasse(self.FContainedObjects[i]).setXPosition(TGrafikBasisKlasse(self.FContainedObjects[i].XPosition) + diffX);
    end; // for i := 0 to self.FCountaindedObjects.Count - 1
  end; // if self.FContainedObjects.Count > 0
end;
Wie gesagt, es sind nur Anregungen, bei der konkreten Umsetzung musst du schauen. Wenn du es so oder ähnlich machst, denke ich solltest du kein Problem bekommen. Werde mir trotzdem gleich noch deinen Code anschauen, vielleicht sehe ich ja dort den Fehler.

Gruß Der Unwissende
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#4

Re: TObjectlist in TObjectList

  Alt 2. Jul 2006, 08:58
Ok,
sorry wenn ich das jetzt mal so sage, aber an deinem Code solltest du noch etwas arbeiten. Ich weiß nicht wie groß das Grafikprogramm ist oder werden soll, aber gerade bei etwas größeren Projekten zahlen sich ein paar Dinge aus. Es gibt nette (kleine) Bücher dazu, die haben so ein paar Grundregeln über guten Codestil drin. Gibt sicherlich auch online etwas..
Die sollte man (imho) berücksichtigen. Also mir hat das echt eine Menge gebracht (nicht falsch verstehen, ist wirklich als Tipp gemeint und hilft häufig Fehler zu vermeiden, Code lesbarer zu machen und auch wartbar und ist gerade bei der Arbeit von mehreren am selben Programm unabdingbar).

Kurz dazu dann ein paar Worte:
  • Variablennamen sollten immer selbst erklären sein (was obj ist weiß doch keiner der es liest)
  • Methodennamen auch (s. BitBnt1.Click, gibt dem Button lieber einen Namen)
  • With solltest du ruhig weglassen. Ist zwar praktisch, führt aber nicht gerade zu leicher lesbarem Code

Ist wirklich nicht so schlimm wie es jetzt vielleicht klingt, aber diese Kleinigkeiten machen Code schnell unübersichtlicher als er sein muss.
Kommen wir zu deinem eigentlichen Problem:


Zitat von mimi:
Delphi-Quellcode:
  if Obj.Count > 0 then
  begin
    for i := 0 to Obj.Count - 1 do
    begin
      if assigned(TFigure(obj.Items[i]).Style.obj1) then
      begin
        // Prüfen ob überhaupt was in der Liste steht!
        if TFigure(obj.Items[i]).Style.obj1.Count > 0 then
        begin
          // Zählvariablen sollten einheitlich mit i, j, k, ... benannt werden
          for x := 0 to TFigure(obj.Items[i]).Style.obj1.Count - 1 do
          begin
          
            // prüfen ob an der Stelle überhaupt etwas steht
            if assigned(TFigure(Obj[i]).Style.obj1.Items[x]) then
            begin
              TFigure(TFigure(Obj[i]).Style.obj1.Items[x]).draw(bmp);
            end; // if assigned(TFigure(Obj[i]).Style.obj1.Items[x])
          end; // for x := 0 to TFigure(obj.Items[i]).Style.obj1.Count - 1
        end; // if TFigure(obj.Items[i]).Style.obj1.Count > 0
    end; // for i := 0 to Obj.Count - 1
  end; // if Obj.Count &gt; 0
Ist trotz allem nicht gerade der schönste Code. Besser ist es, wenn du wirklich getrennte Container und normale Objekte hast. Dann kannst du wirklich das Bewegen automatisieren und hast nicht mehr diese doppelten Casts wie hier. An sich solltest du immer schauen, ob eine Liste zugewiesen ist (assigned(deinObjekt)) und ob sie auch mindestens 1 Element enthält (deinObjekt.Count > 0). Bevor du castest kannst du natürlich auch schauen ob das Element überhaupt vom richtigen Typ ist (deinObjekt is TDeineKlasse). Natürlich musst du das immer nur dann machen, wenn es nicht sichergestellt wird. Hast du also eine Methode, die öffentlich ist oder irgendwie Argumente von "aussen" bekommt, so solltest du solche Tests immer einbauen. Alles was von "aussen" (ausserhalb deiner Klasse) kommt, kann alles beinhalten. Arbeitest du nur mit selbst in der Klasse Erzeugtem, kannst du hier natürlich gewisse Bedingungen garantieren. Damit kannst du dann Prüfungen wegfallen lassen (musst es aber nicht).
Vorteile liegen dann wirklich darin, dass du diese Klassen (die immer die Eingabe prüfen) auch woanders weiter verwenden kannst.
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#5

Re: TObjectlist in TObjectList

  Alt 2. Jul 2006, 09:50
also wegen dem codestyl:
ich finde der ist für mich übersichtlich aber das ist geschmacksache....
das mit den Variabeln bennung undsoweiter hast du natürlichrecht nur ich bin dazu zufaul wenn mir keine auf anhib einfallen die die funktion der variable/procedure beschreiben....
zum With: ich wollte es auch weglassen nur dann kamm ein compiler fehler:
"Linkeseite kann nicht zugewisen werden." das habe ich auch nicht ganzso verstanden. und mit with hat es halt geklappt darum....


zum eigentlichen problem:
ich habe mehre Objekte und jedes objekte soll in der lage sein Weiter Objekte aufzunehmen also ein "Objekt Container" wobei die objekte verschoben werden sollten in das objekte wo ich es hineinziehe....
Ich schreibe in einem team ein grafikprogramm und wenn ich es jetzt umstelle auf OOP können wir gleich von vorne anfangen das wollten wir nicht(ich schon aber)... aber warum hat das mit meiner idee nicht geklappt. Ich hatte doch eine prüfung <> nil gemacht


----
Zitat:
mimi hat folgendes geschrieben:

Delphi-Quellcode: markieren
TStyle = record
obj1:TObjectList;
.....
end;

und nun habe ich eine weiter tList um das object zu verwalten. das heißt so eine art Object Baum.


Eine weitere TList? Wo ist denn die erste TList?
Um das Objekt zu verwalten? Wo ist denn das Objekt? Ein Record ist kein Objekt!
die erste ist im Hauptprogramm defniert und die weitere ist in TStyle defniert.... und installsiert wird sie in der Create procedure.
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#6

Re: TObjectlist in TObjectList

  Alt 2. Jul 2006, 10:13
Zitat von mimi:
zum With: ich wollte es auch weglassen nur dann kamm ein compiler fehler:
"Linkeseite kann nicht zugewisen werden." das habe ich auch nicht ganzso verstanden. und mit with hat es halt geklappt darum....
Das der linken Seite nichts zugewiesen werden kann, sagt der Compiler einfach dann, wenn die linke Seite nicht variabel ist. Das kann ein read-only Property sein, eine Konstante oder Ähnliches. Das würde dann allerdings auch nicht mit With klappen. Und hier liegt das Problem, das With ersetzt ja nur ein Präfix auf der linken Seite (ggf.). Nun ist das Problem, dass du recht schnell nicht mehr weißt was eigentlich auf der linken Seite steht (da die volle Quailifizierung einfach fehlt).

Zitat von mimi:
Ich schreibe in einem team ein grafikprogramm und wenn ich es jetzt umstelle auf OOP können wir gleich von vorne anfangen das wollten wir nicht(ich schon aber)...
Ja, was soll ich dazu noch sagen, solange ihr voran kommt und es läuft. Möchte jetzt nicht besser-wisserisch klingen, aber es gibt so ein paar Dinge, die haben es echt in sich. Ich kann es bei euerm Programm nicht beurteilen, aber man schiebt halt gerne Probleme auf. Je komplexer ein Problem scheint, desto weiter nach hinten schiebt man es und macht erstmal dass, was man leicht lösen kann. Ganz schnell sieht man den Fortschritt (was einen natürlich super motiviert!) und dann kommt irgendwann mal der Punkt, an dem nur noch die großen Probleme warten. Nun ja, je mehr man schon gemacht hat, desto aufwändiger ist das neu-anfangen.
Bei euerm Grafikprogramm kommt der Punkt vielleicht nie und hätte wahrscheinlich auch weniger wilde Konsequenzen, aber wenn es an einem Feature scheitert, dass ein Kunde bezahlt hat...
Also klar, man kann auch heute noch super Programme ohne OOP produzieren, aber es gibt ja Ideen hinter der (sinnvollen) Verwendung und Modellierung mit Objekten. Und mit etwas Erfahrung kann man dort sehr schön sehr mächtigen Code erzeugen (leicht erweiterbar durch Verhaltens- und Objektvererbung).

Gerade wenn ihr im Team arbeitet sollten alle Variablen sofort sinnvoll benannt werden. Es blickt ab einem gewissen Punkt sonst keiner mehr durch (glaub mir, hab da so einige Erfahrung aus eben solchen vermeidbaren Fehlern, die ich mitverschuldet habe).
Sind aber alles nur persönliche Erfahrungen und Meinungen, soll wirklich nur als Anregung nicht als Kritik verstanden werden. Wie gesagt, es geht auch ohne!

Zitat von mimi:
aber warum hat das mit meiner idee nicht geklappt. Ich hatte doch eine prüfung <> nil gemacht
Du prüfst nur ob eine Liste vorhanden ist. Diese Liste kann aber leer sein. Das heißt du hast eine Liste (ok, geprüft) die hat 0 Elemente (das prüfst du nie) und du willst jetzt das erste von diesen 0 Elementen nehmen (du siehst das Problem?)

Zitat von mimi:
die erste ist im Hauptprogramm defniert und die weitere ist in TStyle defniert.... und installsiert wird sie in der Create procedure.
Ok, da ich mir immer noch nicht 100%ig sicher bin, möchte ich an dieser Stelle nur kurz sagen TList <> TObjectList! Dies ist ein wirklich wichtiger Unterschied. Einer TList kannst du nur Zeiger zuweisen. Hier musst du dann wirklich aufpassen, dass der Speicherbereich auf den du zeigst nicht schon irgendwo frei gegeben wurde. Wenn du dir mit New neue Records anlegst, dann hast du diese Sicherheit (und solltest tunlichst auf's freigeben des Speicherbereichs achten). Legst du aber nur eine lokale Variable an und trägst die Speicheradresse dieser lokalen Variable mehrfach als unterschiedliche Elemente (mehrere Aufrufe der Methode) in eine TList ein, du würdest nicht bekommen was du gerne hättest.
Eine TObjectList hingegen speichern nur Instanzen von Klassen. Da jede Klasse von TObject abgeleitet ist, kannst du hier also wirklich Instanzen aller Klassen speichern (musst entsprechend nur casten). Da jedes TObject (und damit alle Nachfahren) auch einen Destruktor haben, kann sich eine TObjectList auch gleich um die freigabe der gespeicherten Objekte kümmern.
Da du sagtest du hast eine weitere TList, ging ich jetzt also von zwei TList Instanzen aus, nicht zwei TObjectList Instanzen. Klingt jetzt vielleicht ein wenig kleinlich, aber es ist ein wirklich wichtiger Unterschied (was die Benutzung angeht), denn während du in einer TList einen Zeiger auf alles speichern kannst, kannst du nicht jeden Zeiger als Objekt in einer TObjectList ablegen sondern eben nur Objekte.
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#7

Re: TObjectlist in TObjectList

  Alt 2. Jul 2006, 10:44
Bei meiner suche bin ich auch auf diese problem gestoßen mit Tlist und TObjectList aber wir verwenden TObjectList.

was sind den objekte:
Klassen
Record ?

ich habe das problem gefunden ist liegt an der Remove funktion von TObjectList nur ich weiß nicht wie ich es andere lösunen kann.
ich zeichne in einen timer alle objekte das habe ich jetzt unterbunden..... Wenn ich den zeichnen vorgang wieder starten möchte kommt wieder die av....
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:15 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz