Object löschen für flexibles Menü

Hi.
Bin mal wieder daran mein Menü für mein LCD zu programmieren.
Vorweg alles läuft soweit. Nur irgendwie hat mich jetzt der ehrgeiz gepackt das Menü etwas flexibler zu gestalten.

Also folgendes Problem:

#include <Menu.h>

#define _LANG_MENU_luefter                                "Luefter"
  #define _LANG_MENU_luefter_automatik                      "Automatik"
  #define _LANG_MENU_luefter_automatik_temperatur           "Temperatur"
  #define _LANG_MENU_luefter_automatik_auswahl              "Auswahl"
....

// Menü Objektstruktur anlegen   
  Menu Item1       (_LANG_MENU_luefter);                    
  Menu Item11      (_LANG_MENU_luefter_automatik);                    
  Menu Item111     (_LANG_MENU_luefter_automatik_temperatur);                         
  Menu Item112     (_LANG_MENU_luefter_automatik_auswahl); 
......

void CONTROL_menu_init()
  {   
    lcd_menu.addChild(Item1);
    lcd_menu.addChild(Item2);
    lcd_menu.addChild(Item3);
      Item1.addChild(Item11);
      Item1.addChild(Item12);
....
}

Mein Problem besteht jetzt darin, dass ich z.B. in einem Untermenü 6 Lüfter habe und möchte nun das der User die Anzahl verringern kann.
Habe also in den "Einstellungen" eine Funktion geschrieben, in der ich die Anzahl abfrage.
Jetzt ist das Problem, dass die menu.h nur addchild Funktionen hat und keine remove/deletechild.
Da ich es ehrlich gesagt auch schon immer sehr strubbelig fand mit den Pointern ( ich verstehe das Grundprinzip von Adresse/Pointer und co) habe ich mir gedacht, lass die Finger da weg es muss doch einfacher gehen.
Hatte also die Idee einfach im Nachhinein das Objekt einfach zu löschen, da ich ja für jedes child ein neues Objekt anlege. Wieder hinzufügen könnte ich dann ja wieder per addchild() machen.
Das Problem ist nur ich kriege zum verrecken nicht das Objekt gelöscht um zu ob es so überhaupt funktioniert.

Hatte es schon versucht mit:

      delete Item1;

Ergebnis:

aktuell:1757: error: type 'class Menu' argument given to 'delete', expected pointer

Interpretiere ich einfach mal so, dass er über delete keine Objekte löschen kann sondern nur Pointer!? Wenn ja, könnte ich ja die Pointer löschen die auf mein child zeigen, welches ich löschen will, wenn die nicht vorhanden sind, kann ja an sich auch nichts angezeigt werden. Ist mir ja an sich egal ob das Objekt dann noch da ist oder nicht.
Sollte das mit den Pointern, hat jemand eine Ahnung wie genau dann der Befehl dafür aussieht, da hörts dann bei mir wieder auf.

Hatte es schon versucht mit:

      ~ Item1;

Ergebnis:

aktuell:1757: error: no match for 'operator~' in '~Item1'

Irgendwie hatte ich im hinterkopf, dass man mit ~ Objekte löschen kann.

Vielen Dank für Hilfe oder Tipps!
Gruß
Kevin

Einen Fehler habe ich gerade gesehen, ich darf nicht mit Item1 oder so arbeiten, da die durch die Erstellung umbenannt wurden.

Du kannst nur Objekte löschen, die Du nicht als lokale Objekte definiert sind. Du müsstest Deine Menüs also so erstellen:

Menu *Item1 = new Menu(_LANG_MENU_luefter);

Dann kannst Du die Objekte auch wieder löschen:

delete Item1;

Allerdings musst Du dann vorsichtig sein, wenn sie anderswo noch referenziert sind, was bei einem addChild() der Fall sein dürfte.

Da Du Deine Bibliothek (Menu.h) nicht verlinkt hast und sie nicht der im Playground verlinkten Version zu entsprechen scheint (dort heisst der Punkt addMenuItem()), kann ich Dir nicht sagen, ob die Bibliothek das Entfernen unterstützt. Auf jeden Fall ist Dein Problem nicht das Löschen eines Objekts, sondern die Bibliothek muss das Entfernen eines Menüpunkts unterstützen.

Okay dumm von mir, sry.

Hier ist die library:

/*
Menu.cpp - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want

*/

//#include "WProgram.h"
#include "Menu.h"

void Menu::setParent(Menu &p)
{
parent=&p;
}

void Menu::addSibling(Menu &s,Menu &p)
{
if (sibling)
 {
 sibling->addSibling(s,p);
}
else
 {
 sibling=&s;
 sibling->setParent(p);
 }
}

Menu::Menu(char *n)
{
name=n;
canEnter=NULL;
}

Menu::Menu(char *n,boolean (*c)(Menu&))
{
name=n;
canEnter=c;
}

void Menu::addChild(Menu &c)
{
if (child)
 {
 child->addSibling(c,*this);
 }
else
 {
 child=&c;
 child->setParent(*this);
 }
}

Menu * Menu::getChild(int which)
{
if (child)
 {
 return child->getSibling(which);
 }
else //This Menu item has no children
 {
 return NULL;
 }
}

Menu * Menu::getSibling(int howfar)
{
if (howfar==0)
 {
 return this;
 }
else if (sibling)
 {
 return sibling->getSibling(howfar-1);
 }
else //Asking for a nonexistent sibling
 {
 return NULL;
 }
}

Menu * Menu::getParent()
{
if (parent)
 {
 return parent;
 }
else //Top Menu
 {
 return this;
 }
}
/*
Menu.h - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want

*/
#ifndef Menu_h
#define Menu_h

#include "arduino.h"

class Menu
{
private:
 Menu * parent;//Parent Menu, NULL if this is the top
 Menu * child;//First Child Menu, NULL if no children
 Menu * sibling;//Next Sibling Menu, NULL if this is the last sibling

 void setParent(Menu &p);//Sets the Menu's Parent to p
 void addSibling(Menu &s,Menu &p);//Adds a Sibling s with Parent p.  If the Menu already has a sibling, ask that sibling to add it
public:
 char *name;//Name of this Menu
 boolean (*canEnter)(Menu&);//Function to be called when this menu is 'used'

 Menu(char *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
 Menu(char *n,boolean (*c)(Menu&));//Constructs the Menu with a specified use function
 void addChild(Menu &c);//Adds the child c to the Menu.  If the menu already has a child, ask the child to add it as a sibling
 Menu * getChild(int which);//Returns a pointer to the which'th child of this Menu
 Menu * getSibling(int howfar);//Returns a pointer to the sibling howfar siblings away from this Menu
 Menu * getParent();//Returns this Menu's parent Menu.  If no parent, returns itself
};

#endif //Menu_h

Das mit dem delete seh ich auch ein, hatte es zwar das ein oder andere mal gelesen, konnte jedoch nicht sehr viel mit anfangen.

Bin mittlerweile auch soweit, dass es auch klüger ist "einfach" den Pointer an sich zu löschen und ihn als NULL zu setzen.
Steh da leider genauso auf dem Schlauch, da ich durch die Vererbung nicht weiß wie ich den Pointer ansprechen soll.

So.. für Hilfe bin ich wie immer mehr als dankbar!
Gruß
Kevin

Auch Deine Bibliothek hat keine Methode, ein eingetragenes Menü wieder zu löschen. Du müsstest diese Funktionalität also ergänzen. Da die Menüs in einer einfach verketteten Liste gehalten werden, sollte dies nicht allzu schwer zu bewerkstelligen sein.

Bin mittlerweile auch soweit, dass es auch klüger ist "einfach" den Pointer an sich zu löschen und ihn als NULL zu setzen.
Steh da leider genauso auf dem Schlauch, da ich durch die Vererbung nicht weiß wie ich den Pointer ansprechen soll.

Ich verstehe Deine Aussage nicht. Das Löschen des Pointers nützt Dir nichts und wenn Du ihn auf NULL setzt, dann verlierst Du nur seine Referenz und hast somit ein Memory Leak. Mit Vererbung hat das auch nichts zu tun.

Das es in der library nicht enthalten ist war mir klar, da schaue ich ja nunmal als erstes nach.

Und das mit der Ausssage war so gemeint, dass ich versteh nicht ganz nach welchem Prinzip die Pointer in der Vererbung abgerufen werden, jedoch lang es vllt. einfach den Pointer auf mein zu löschendes Objekt zu löschen. Sollte der speicher weiterhin noch belegt sein macht mir das eigentl. nicht viel.

Du müsstest diese Funktionalität also ergänzen

Das Problem ist ja gerade, dass ich keine Ahnung habe wie.

Da ich schon sehr viel mit der Menü Klasse gearbeitet habe und meine LCDMenu2 Lib auch darauf aufbaut würde ich einen anderen Weg gehen.

Du kannst über das Menü z.B. die Auswahl der Lüfter vornehmen. Die Anzahl die gebraucht werden speicherst du dann im EEPROM ab.
Beim ersten Starten des Kontrollers lädst du erst die Werte aus dem EEPROM und generierst danach einmalig die Objektstruktur mit

if(EEPROM.read(......)) {
   Menu Item112     (_LANG_MENU_luefter_automatik_auswahl);
}
...
...

void CONTROL_menu_init()
  {   
    lcd_menu.addChild(Item1);
    lcd_menu.addChild(Item2);
    lcd_menu.addChild(Item3);
      Item1.addChild(Item11);
      if(EEPROM.read(......)) {
            Item1.addChild(Item12);
      }
....

Da dieser Code nur einmalig ausgeführt wird, wird dein Programm dadurch nicht langsamer.
Der einzige Nachteil ist, dass der Anwender den Kontroller neustarten muss.
Alternative kannst du auch eine Funktion schreiben die den Kontroller dann neustartet.

Zur Laufzeit mit Objekten rum zu spielen , sprich löschen und dynamisch neu erstellen würde ich bei einem 8Bit Mikrocontroller nie machen, da ansonsten schnell ein Fehler auftritt. Unkontrollierte Speicherüberläufe usw. Die Fehler sind dann richtig schwer zu finden.

Das ist doch mal eine Ansage! Zwar nicht das was ich hören wollte, aber bringt mich dennoch weiter.

Die if Abfrage habe ich auch schon drin, nur ich wollte es an sich zur Laufzeit machen.

Wie schreibe ich denn sowas ins EEPROM? Hatte mir die ganzen Speichertypen mal durchgelesen, aber nie wirklich mit gearbeitet.

Heisst doch soviel, dass ich dort eine Variable rein schreibe die nach dem Neustart immer noch vorhanden ist oder?
Gibt es einen Befehl zum reset?

Das ist das erweiterte Menu.h:

/*
Menu.h - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want

*/
#ifndef Menu_h
#define Menu_h

#include "arduino.h"

class Menu
{
private:
 Menu * parent;//Parent Menu, NULL if this is the top
 Menu * child;//First Child Menu, NULL if no children
 Menu * sibling;//Next Sibling Menu, NULL if this is the last sibling

 void setParent(Menu &p);//Sets the Menu's Parent to p
 void addSibling(Menu &s,Menu &p);//Adds a Sibling s with Parent p.  If the Menu already has a sibling, ask that sibling to add it
 void removeSibling(Menu &c);//Removes the sibling from the Menu's siblings
public:
 char *name;//Name of this Menu
 boolean (*canEnter)(Menu&);//Function to be called when this menu is 'used'

 Menu(char *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
 Menu(char *n,boolean (*c)(Menu&));//Constructs the Menu with a specified use function
 void addChild(Menu &c);//Adds the child c to the Menu.  If the menu already has a child, ask the child to add it as a sibling
 void removeChild(Menu &c);//Removes the child from the Menu
 Menu * getChild(int which);//Returns a pointer to the which'th child of this Menu
 Menu * getSibling(int howfar);//Returns a pointer to the sibling howfar siblings away from this Menu
 Menu * getParent();//Returns this Menu's parent Menu.  If no parent, returns itself
};

#endif //Menu_h

und das Menu.cpp:

/*
Menu.cpp - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want

*/

//#include "WProgram.h"
#include "Menu.h"

void Menu::setParent(Menu &p)
{
parent=&p;
}

void Menu::addSibling(Menu &s,Menu &p)
{
if (sibling)
 {
 sibling->addSibling(s,p);
}
else
 {
 sibling=&s;
 sibling->setParent(p);
 }
}

Menu::Menu(char *n)
{
name=n;
canEnter=NULL;
}

Menu::Menu(char *n,boolean (*c)(Menu&))
{
name=n;
canEnter=c;
}

void Menu::addChild(Menu &c)
{
if (child)
 {
 child->addSibling(c,*this);
 }
else
 {
 child=&c;
 child->setParent(*this);
 }
}

void Menu::removeChild(Menu &c)
{
if (child)
 {
 if (child==&c)
  {
  child=child->getSibling(1);
  c.parent=NULL;
  c.sibling=NULL;
  }
 else
  {
  child->removeSibling(c);
  }
 }
}

void Menu::removeSibling(Menu &c)
{
if (sibling)
 {
 if (sibling==&c)
  {
  sibling=sibling->getSibling(1);
  c.parent=NULL;
  c.sibling=NULL;
  }
 else
  {
  sibling->removeSibling(c);
  }
 }
}

Menu * Menu::getChild(int which)
{
if (child)
 {
 return child->getSibling(which);
 }
else //This Menu item has no children
 {
 return NULL;
 }
}

Menu * Menu::getSibling(int howfar)
{
if (howfar==0)
 {
 return this;
 }
else if (sibling)
 {
 return sibling->getSibling(howfar-1);
 }
else //Asking for a nonexistent sibling
 {
 return NULL;
 }
}

Menu * Menu::getParent()
{
if (parent)
 {
 return parent;
 }
else //Top Menu
 {
 return this;
 }
}

Du kannst jetzt die Methode removeChild() benutzen, um ein Menu aus der Menu-Struktur zu entfernen. Speicherfreigabe ist weiterhin Deine Aufgabe, und glaube mir, es macht viel, wenn der Speicher weiterhin belegt ist. Vergiss nicht, der Arduino hat nur 2kB davon und wenn er ausgeht, sind die Folgen praktisch unvorhersehbar, von einfrieren bis ausser Rand und Band laufen.

Super dank dir! Werde mal sehen wie ich das hinkriege! :slight_smile: