Announcement

Collapse
No announcement yet.

Combobox und AddObjects bringt mir Speichermüll zurück

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Combobox und AddObjects bringt mir Speichermüll zurück

    Hallo Leute,

    ich habe das Problem, dass ich in einer Combobox mir Feldüberschriften und mit AddObjects die passenden Feldnamen anzeigen bzw. ermitteln will. Ich fülle die ComboBox wie folgt:

    for i := 0 to qry_His_Historie.FieldCount -1 do

    cb_SuchFeld1.Items.AddObject(qry_His_Historie.Fiel ds[i].DisplayName, TObject(pchar(qry_His_Historie.Fields[i].FieldName)));

    Wenn ich nun auf den Feldnamen zugreifen will, dann mache ich das wie folgt:

    cFeld1 := pchar(cb_SuchFeld1.Items.Objects[cb_SuchFeld1.ItemIndex]);

    Beim ersten mal klappt es immer, wenn ich aber erneut auf das Feld zugreife bekomme ich nur noch Sonderzeichen bzw. verstümmelte Feldnamen zurück. Das Sonderbare ist, dass es manchmal auch zwei, bzw. dreimmal klappt und dann kommt Müll zurück.

    Ich finde aber keinen Fehler. :-((

    Hat einer vielleicht einen Rat für mich? Helfen tue ich mir gerade so, dass ich die Combobox mit .Clear leere und dann erneut einlese. So klappt es, ist aber leider nicht so toll da ich dem Anwender gerne es ermöglich möchte die Letzte Suchabfrage zu behalten.

    Gruß
    Axel

  • #2
    Hallo Axel,<br>mit
    cb_SuchFeld1.Items.AddObject(qry_His_Historie.Fiel ds[i].DisplayName, TObject(pchar(qry_His_Historie.Fields[i].FieldName))); speicherst Du in Objects nicht den String, sondern einen Zeiger auf die Speicherstelle, wo qry_His_Historie.Fields[i].DisplayName steht. Wenn jetzt die Query freigegeben o. sich ändert, wird diese Stelle im Speicher überschrieben. Dann zeigt Objects auf irgendwas aber nicht auf den Displayname. D.h. es geht solange gut, bis die Speicherstelle überschrieben wird.<br>Ich nutze die Objects Eigenschaft sehr oft. Ich kapsel den String dann immer in einem Objekt. Das verursacht zwar mehr Schreibarbeit, läßt sich aber besser handhaben. Besonders dann, wenn man später mehr Info's speichern will. Da braucht man nur das Objekt zu erweitern

    Comment


    • #3
      Hallo Jens,

      das mit dem zeiger hört sich logisch an. Wenn ich also über eine Zwischenvariable mir den Wert merke, dann solte es doch klappen oder?
      <PRE>
      cVar1 : string
      ...
      cVar1:= qry_His_Historie.Fields[i].FieldName;
      ...
      cb_SuchFeld1.Items.AddObject(qry_His_Historie.Fiel ds[i].DisplayName, TObject(pchar(cVar1)))
      ...
      </PRE>
      Liege ich da richtig? Hast Du ein Beispiel für die Verwendung mit einem Objekt, wie Du es nutzt?

      Danke für die Mühe.

      Gruß
      Axe

      Comment


      • #4
        Moin Axel,<br>ungefähr so <pre>
        unit Unit1;

        interface

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

        type
        TListboxData = class(TObject)
        private
        FFieldname;
        public
        property Fieldname : String read FFieldname write FFieldname;
        end;

        TForm1 = class(TForm)
        ListBox1: TListBox;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        private
        { Private-Deklarationen }
        public
        { Public-Deklarationen }
        end;

        var
        Form1: TForm1;

        implementation

        {$R *.DFM}

        procedure TForm1.Button1Click(Sender: TObject);
        var
        ListboxData : TListboxData;
        begin
        For iCnt:=0 to qry_His_Historie.Fields.Count-1 do
        begin
        ListboxData:=TListboxData.Create;
        ListboxData.Fieldname:=qry_His_Historie.Fields[iCnt].FieldName;
        Listbox1.Items.AddObject(qry_His_Historie.Fields[iCnt].DisplayName,ListboxData);
        end;
        end;

        procedure TForm1.FormDestroy(Sender: TObject);
        var
        iCnt : Integer;
        begin
        For iCnt:=0 to Listbox1.Items.Count-1 do
        Listbox1.Items.Objects[iCnt].Free;
        end;

        end.</pre&gt

        Comment


        • #5
          Hallo Jens,

          danke für das Beispiel. Ich habe noch immer ein Problem
          Hier bekomme ich einen Fehler:

          <PRE>
          type
          TListboxData = class(TObject)
          private
          FFieldname; !!! Hier bekomme ich einen Fehler !!!!
          public
          property Fieldname : String read FFieldname write FFieldname;
          end; TForm1 = class(TForm)
          ListBox1
          </PRE>

          Wie komme ich an die Feldnamen wieder dran???

          Gruß
          Axe

          Comment


          • #6
            Hallo Axel,<br>
            mein Fehler. Es muß natürlich FFieldname : String; heißen.<br>An den Feldnamen kommst Du wie folgt:<br>
            Name:=TListBoxData(Listbox1.Items.Objects[Listbox1.ItemIndex]).Fieldname;<br>Ich habe auch noch etwas anderes vergessen. Wenn Du die Listbox mehr als einmal befüllen möchtest, mußt Du vorher alle über die Listbox1.Items.Objects Eigenschaft referenzierten Objekte freigeben !!!<pre>
            For iCnt:=0 to Listbox1.Items.Count-1 do
            Listbox1.Items.Objects[iCnt].Free;
            </pre&gt

            Comment


            • #7
              Hallo Jens,

              DANKE!! Das klappt jetzt super. Wenn Du mir nur noch sagen könntest, wie ich nach den Inhalt eines Objektes suchen kann?? So funktioniert es nicht:

              <PRE>
              cFeld := trim(qry_Abfrage.FieldByName('FELD_1').asString);
              cB_SuchFeld1.ItemIndex := cb_H_SuchFeld1.Items.IndexOfObject(TListBoxData(cF eld));
              </PRE>

              Ich wollte den in einer Tabelle gespeicherten Namen wieder auflösen. In der Tabelle Feld "FELD_1" steht NAME_1 drin. In der ComboBox steht an der Stelle x der Eintrage "Nachname" und als TListBoxData-Objekt der eintrag "NAME_1" als Feldbezeichner für Nachname. Nun will ich den NAME_1 aus der Tabelle lesen und gleich den richtigen Eintrag selektieren. Warum geht es nicht so wie in meinem Beispiel?

              Noch einmal vielen Dank für Deine bereits geleistete schnelle Hilfe.

              Gruß
              Axe

              Comment


              • #8
                Hallo Axel,<br>
                cFeld ist vom Type String. Die Objects Eigenschaft hat den Type TObject.<br>
                Mit TListBoxData(cFeld) versucht einen String in ein TObject zu casten (TypeCasting).<br>
                Das kann nicht klappen.<br>
                IndexOfObject erwartet als Pararmter ein TObject. D.h. IndexOfObject vergleicht intern<br>
                die Adresse des Paramters mit den in Objects gespeicherten "Objectadressen". Wenn zwei übereinstimmende Adressen<br>
                gefunden wurden, gibt IndexOfObject den Index innerhalb der Liste zurück. Wenn nicht wird -1 zurückgeliefert.<br>
                Eine Suchfunktion könnte so aussehen:<pre>
                <font face="Verdana" size="1" color="#000000">function TForm1.GetItemIndex(const S : String) : Integer;
                var
                iCnt : Integer;
                begin
                Result:=-1;
                For iCnt:=0 to cB_SuchFeld1.Items.Count-1 do
                begin
                If TListBoxData(cB_SuchFeld1.Items.Objects[iCnt]).Fieldname=S then
                begin
                Result:=iCnt;
                Exit;
                end;
                end;
                end;

                ...
                cFeld := trim(qry_Abfrage.FieldByName('FELD_1').asString);
                cB_SuchFeld1.ItemIndex := GetItemIndex(cFeld);
                ...</font>
                </pre&gt

                Comment

                Working...
                X