TList auf Items[i] zugreifen?



  • Hallo zusammen, ich verzweifle und bekomme es einfach nicht gebacken....
    ich möchte in der Liste Int Werte ablegen, löschen nach Wert und gesamten Inhalt von aktueller Liste ausgeben, was mach ich falsch?
    mein file.h

    //---------------------------------------------------------------------------
    
    #ifndef fileH
    #define fileH
    //---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <Vcl.Controls.hpp>
    #include <Vcl.StdCtrls.hpp>
    #include <Vcl.Forms.hpp>
    #include <Vcl.ComCtrls.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
    	TEdit *EditInput;
    	TButton *ButtonAdd;
    	TButton *ButtonDel;
    	TButton *ButtonRes;
    	TRichEdit *RichEditOutput;
    	void __fastcall ButtonAddClick(TObject *Sender);
    	void __fastcall ButtonDelClick(TObject *Sender);
    	void __fastcall ButtonResClick(TObject *Sender);
    private:	// Benutzer-Deklarationen
    public:		// Benutzer-Deklarationen
    	TList* Liste;
    	enum _status
    	{
    		add = 1,//hinzufügen
    		del = 2,//entfernen
    		res = 3,//ergebnis
        };
    	__fastcall TForm1(TComponent* Owner);
    	void __fastcall AddValue(_status betrieb, int val);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    

    mein file.cpp

    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "file.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner)
    {
    	Liste = new TList();
    }
    void __fastcall TForm1::AddValue(_status betrieb,int val)
    {
    	if( betrieb == add)
    	{
    		bool doppelt = false;
    		for (int i =0; i < Liste->Count; i++)
    		{
    			if(&val == Liste->Items[i])
    			{
    				doppelt = true;
    			}
    			else
    			{
    				continue;
    			}
    		}
    		if(!doppelt)
    		{
    			Liste->Add(&val);
    		}
    	}
    	else if (betrieb == del)
    	{
    		bool doppelt = false;
    		for (int i =0; i < Liste->Count; i++)
    		{
    			if(&val == Liste->Items[i])
    			{
    				doppelt = true;
    			}
    			else
    			{
    				continue;
    			}
    		}
    		if(!doppelt)
    		{
    			Liste->Remove(&val);
    		}
    	}
    	else if (betrieb == res)
    	{
    		String tempString;
    		int temp2Int;
    		for (int i =0; i < Liste->Count; i++)
    		{
    			//
    			tempString += "/n";
    			temp2Int = (int)Liste->Items[i];
    			tempString += temp2Int;
    		}
    		Form1->RichEditOutput->Text += tempString;
    	}
    	else
    	{
            Form1->EditInput->Text = "FATAL ERROR";
    	}
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ButtonAddClick(TObject *Sender)
    {
    	Form1->EditInput->NumbersOnly=true;
    	int inputValue = EditInput->Text.ToInt();
    	AddValue(TForm1::add,inputValue);
    	Form1->EditInput->Text = NULL;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ButtonDelClick(TObject *Sender)
    {
    	Form1->EditInput->NumbersOnly=true;
    	int inputValue = Form1->EditInput->Text.ToInt();
    	AddValue(TForm1::del,inputValue);
    	Form1->EditInput->Text = NULL;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ButtonResClick(TObject *Sender)
    {
    	int inputValue = NULL;
    	AddValue(TForm1::res,inputValue);
    }
    //---------------------------------------------------------------------------
    


  • @Feuerschmiede Du arbeitest mit der Adresse von val, nicht mit dem Wert.

    val ist aber eine lokale Variable. Die ist nach dem verlassen der Funktion ungültig.



  • Da kann man konzeptionell noch was verbessern:

    1. Benutze GUI Elemente nicht zur Datenhaltung! Sie sollten Daten anzeigen, aber nicht besitzen. Trenn' also Datenhaltung und Anzeige, damit tust du dir langfristig einen Gefallen.

    2. Benutz' den ganzen Delphi Kram nur für's GUI, nimm für alles andere C++. Versuch' also Delphi zu vermeiden, wo immer es geht.



  • @DirkB Dankeschön für den Hinweis.

    @DocShoe (für 1.)wie meinst du zur Datenhaltung? Hast du evenutell ein Bsp. für mich, dass ich mir das besser vorstellen kann?(für 2.) du meinst einen andere IDE?



  • @Feuerschmiede sagte in TList auf Items[i] zugreifen?:

    Hast du evenutell ein Bsp. für mich, dass ich mir das besser vorstellen kann?(für 2.) du meinst einen andere IDE?

    Nein, er meint Aufgabentrennung. Eine Klasse, eine Aufgabe. Pack Deine Daten in Datenstrukturen. Die GUI kann dann dort nachfragen was sie darstellen soll.

    SOLID: The First 5 Principles of Object Oriented Design



  • @Feuerschmiede sagte in TList auf Items[i] zugreifen?:

    @DirkB Dankeschön für den Hinweis.

    @DocShoe (für 1.)wie meinst du zur Datenhaltung? Hast du evenutell ein Bsp. für mich, dass ich mir das besser vorstellen kann?(für 2.) du meinst einen andere IDE?

    Da hab ich wohl wieder mal was gelesen, was ich lesen wollte. Ich dachte, eine TList wäre das TListView-Element.
    Viele Delphi Klassen haben den Nachteil, dass man sie auf dem Heap erzeugen muss, wie zB TList in deinem Beispiel. Das hat zur Folge, dass man sie auch wieder per delete löschen muss oder sie gleich in einen smart pointer wie std::unique_ptr oder std::shared_ptr verpackt. Aber Achtung: Auch da hat Delphi wieder seine Tücken, std::make_shared führt bei einigen Klassen zu Zugriffsverletzungen, weil Delphi da wieder iwas im Hintergrund macht, das damit inkompatibel ist. Die Details dazu habe ich nicht mehr auf dem Schirm, ich kann mich nur daran erinnern, dass ich damit mal böse auf die Nase gefallen bin. Aus diesen ganzen Geschichten habe ich gelernt, Delphi wirklich nur für das GUI zum Anzeigen der Daten zu benutzen, für alles andere benutze ich C++.

    Und konkret zu deinem Code:
    Du benutzt die Funktion TForm1::AddValue() für drei Aufgaben:

    1. Einen Wert in die Liste einfügen
    2. Einen Wert aus der Liste löschen
    3. Inhalt der Liste in einem Textfeld ausgeben

    Das sind zwei Aufgaben zu viel für eine Funktion, jede Funktion sollte genau eine Aufgabe haben.
    Für Aufgabe 1) macht der Name der Funktion Sinn, für alle anderen nicht. Wenn ich iwo AddValue lese gehe ich nicht davon aus, dass sie irgendwas in einem Textfeld ausgibt. Wenn man jetzt wirklich weit ausholt könnte man sich Datenstrukturen bauen, die selbst Ereignisse erzeugen und verschicken, aber das ist in deinem Beispiel wohl mit Kanonen auf Spatzen schießen. Trotzdem kann man es relativ einfach besser und übersichtlicher machen:

    // Eine .h/.cpp Datei, die deine Daten hält
    
    #include <set>
    #include <string>
    #include <sstream>
    #include <algorithm>
    
    class MyDataIrgendwas
    {
       // in C++ gibt es verschiedene Container, die mehrere Elemente verwalten können. std::vector ist da die erste Wahl, wenn man einfach 
       // mehrere Elemente speichern möchte und es sonst keine weiteren Anforderungen gibt. std::set hat die Eigenschaft, keine Duplikate 
       // zuzulassen und die Elemente automatisch zu sortieren. Falls die Sortierung in deinem Fall nicht gewünscht ist kann man zu std::vector 
       // wechseln, dann sehen die Funktionen zum Finden eines Elements etwas anders aus.
       std::set<int> Data_;
    
    public:
       MyDataIrgendwas() = default;
    
       void add_value( int value )
       {
          // std::set lässt keine Duplikate zu, also kann hier ohne Überprüfung jeder Wert eingefügt werden, ohne das Duplikate entstehen
          Data_.insert( value );
       }
    
       void remove_value( int value )
       {
          // iterator auf gesuchtes Element finden. Wenn der iterator nicht ungültig ist kann er zum Löschen des Elements benutzt werden.
          auto pos = Data_.find( value );
          if( pos != Data_.end() )
          {
             Data_.erase( pos );
          }
       }
    
       std::string to_string() const
       {
          // alle Elemente des std::set in einen string-ausgabestrom schreiben, nach jedem Element ein "\n" anhängen.
          std::ostringstream oss;
          std::copy( Data_.begin(), Data_.end(), std::ostream_iterator<int>( Data_ ), "\n" );   
          return oss.str();
    };
    
    ...
    
    void TForm1::AddValue()
    {
       MyData_.add_value( EditInput->Text.ToInt() );
       ShowValues();
    }
    
    void TForm1::RemoveValue()
    {
       MyData_.remove_value( EditInput->Text.ToInt() );
       ShowValues();
    }
    
    void TForm1::ShowValues()
    {
       Form1->RichEditOutput->Text = String( MyData_.to_string() );  
    }
    
    void TForm1::OnClickButtonAdd( TObject* Sender )
    {
       AddValue();
    }
    
    void TForm1::OnClickButtonRemove( TObject* Sender )
    {
       RemoveValue();
    }
    
    • der Einfachheit halber kannst du MyDataIrgendwas als Member des Formulars anlegen, aber wenn du irgendwann Anwendungen hast,
      bei denen mehrere Formulare auf die Daten zugreifen musst du dir überlegen, ob das an anderer Stelle nicht besser wäre.
    • mach dich mit der STL (Standard Template Library) vertraut, wenn man C++ programmieren möchte ist das ein absolutes Muss!!!111elf.Wirklich.
      Manche Konzepte wie iteratoren und Prädikate sind für Anfänger sicher verwirrend, aber wenn man das ein mal verstanden hat möchte man nicht
      mehr ohne.
    • lernst du aus einem Buch? Wenn nicht, dann besorg' dir eins und lerne danach (zB. "Der C++ Programmierer" von Ulrich Breymann).
      AUF GAR KEINEN FALL IWAS VON JÜRGEN WOLF!

    PS:
    Was swordfish meint geht noch einen Schritt weiter, aber ich denke, das lohnt sich in diesem Fall noch nicht.
    Das Datenmodell könnte selbst noch ein Publisher für Ereignisse sein, z.B. wenn ein Element hinzugefügt oder entfernt worden ist wird ein Ereignis
    ausgelöst und alle Subscriber benachrichtigt. Überall, wo man an diesen Änderungen interessiert ist, meldet man sich als Subscriber für das
    entsprechende Ereignis an und wird dann automatisch benachrichtigt, wenn dieses Ereignis eintritt, sodass man darauf reagieren kann.



  • @Swordfish dankeschön für den Link habe ich mir schon zum Teil angesehn noch nicht ganz fertig👍🏼
    @DocShoe dankeschön dass du dir die Zeit genommen hast um mir das verständlich und ausfühlich zu erklären👍🏼
    Habe das Buch C++ programmieren ulrich BREYMANN 6 . Auflage
    Ah okay😀



  • @DocShoe

    Benutz' den ganzen Delphi Kram nur für's GUI, nimm für alles andere C++. Versuch' also Delphi zu vermeiden, wo immer es geht.

    Ich dacht immer, Delphi kennt nur Pascal. Ich vermute du meinst C++Builder / VCL/LCL Zeugs ?



  • @Feuerschmiede sagte in TList auf Items[i] zugreifen?:

    Hallo zusammen, ich verzweifle und bekomme es einfach nicht gebacken....
    ich möchte in der Liste Int Werte ablegen, löschen nach Wert und gesamten Inhalt von aktueller Liste ausgeben, was mach ich falsch?

    So wie ich sehe, sucht du mit einer for-Schleife deine Werte. Dafür gibt es index := TList.IndexOf(val), dies spuckt dir die Position aus, wo "val" steht. Und wen er es nicht findet, gibt es -1. In Delphi ist es so, und in C++Builder ist es ähnlich.



  • @Mathuas dankeschön für den Hinweis😀 👍


Anmelden zum Antworten