Forum: Compiler & IDEs menu.h dynamisch menu-Objekte hinzufügen


von Andreas F. (codecasa)


Lesenswert?

Hab wieder ein Problem mit dem dynamischen hinzufügen von menu 
ObjektenWie kann man das am besten machen ?

Also im moment siet es so aus:

   Menu top("Root");
   LCDMenu2 Root(top, lcd , 4, 20, 0, 1);

    Menu Item1("Jobs");
    Menu Item11("Job 01");
    Menu Item12("Job 02");
etc.....


Und in der void setup() führe ich folgenden code aus:
        top.addChild(Item1);
          Item1.addChild(Item11);
          Item1.addChild(Item12);
          Item1.addChild(Item13);
          Item1.addChild(Item14);
etc


Jetzt kommts:
void pUploaded()
{
    for(int ix=0;ix<anzCMD-1;ix++)
    {

    }
    Menu tmpMENU_01("Test1");
    Menu tmpMENU_02("Test2");
    Menu tmpMENU_03("Test3");
    Menu tmpMENU_04("Test4");

    Item11.addChild(tmpMENU_01);
    Item11.addChild(tmpMENU_02);
    Item11.addChild(tmpMENU_03);
    Item11.addChild(tmpMENU_04);

    //Serial.println("Menu erzeugt");

    menu();
    Root.goMenu(top);

}


wenn ich dann in das Menu von Job01 gehe sprich Item11 komt halbwegs nur 
mist aus anderen speicherbereichen:
wie :
Test1

Test2
EEEEEE
/&()?==( und so weiter


Desweiteren würde ich die Menupunkte gerne wie eine array also per 
for-schleife hinzufügen.

von Mark B. (markbrandis)


Lesenswert?

Welchen Scope haben denn tmpMENU_01 und so weiter? Existieren die nur 
lokal, also innerhalb von pUploaded()?

Je nachdem könnte es dann vielleicht eher so gehen (ist nicht wirklich 
getestet da ich grad keinen Compiler zur Verfügung hab):

1
Menu* tmpMENU[4];
2
char str[6];
3
4
for(int i=0; i<3; i++) {
5
    sprintf(str, "Test%d\0", i+1);
6
    tmpMENU[i] = new Menu(str);
7
    Item11.addChild(tmpMENU[i]);
8
}

Ja es ist eine wilde Mischung aus C++ und C, aber der Threadersteller 
hat die Sprache ja nicht genannt - von daher ;-)

von Andreas F. (codecasa)


Angehängte Dateien:

Lesenswert?

Im anhang ist die Menu.H

Ich glaube der constructor functioniert nicht mit new auserdem ist new 
nicht ein Syntax von C++ ?

Ich benutze Arduino das ist C

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:
> Im anhang ist die Menu.H
>
> Ich glaube der constructor functioniert nicht mit new

Doch. Tut er.

> auserdem ist new
> nicht ein Syntax von C++ ?
>
> Ich benutze Arduino das ist C

komisch.
Deine ganze Menu.cpp ist aber in C++ geschrieben.

Aber du hast schon recht: new möchte man eigentlich nicht auf einem µC 
in dieser Leistungsklasse verwenden, wenn es nicht sein muss.
Leg dir ein Array vom Menu Objekten 'als Vorrat' an (in Form eines 
Arrays), und wenn du einen Menüpunkt erzeugen musst, dann "holst" du dir 
ein derartiges Objekt aus diesem Pool (in der Form, dass du seine 
Adresse benutzt), weißt ihm die gewünschten Werte zu und lässt ihn vom 
Menü einbinden. Da sich Menüs ja nicht großartig zur Laufzeit ändern, 
reicht dazu wahrscheinlich eine ganz einfache Poolverwaltung, indem man 
einfach eine Variable mitführt, wieviele Objekte des Arrays schon 
'verbraucht' wurden. Alternativ könnte man auch die im Pool vorhandenen 
Objekte über einen der bereits vorhandenen Pointer in einer Freelist 
verketten. Dann geht das ganze auch komplett dynamisch, mit der einzigen 
Einschränkung, dass die maximale Anzahl an gleichzeitig verwendbaren 
Menu Objekten begrenzt ist. Das ist zwar im Prinzip nicht wirklich 
kompliziert, im Hinblick auf deine bisherigen 'Problemkreise' denke ich 
aber, das es dich noch überfordert so eine Poolallokierung mittels 
Freelist nach den Regeln der C++-Kunst zu machen.

Du müsstest dir dann eben noch einen Default Konstruktor dazu machen. 
Ist ja jetzt nicht das große Problem.

von Karl H. (kbuchegg)


Lesenswert?

Und nochwas:
Du brauchst dringend etwas Literatur.
Solche Dinge wie Scope, dürfen für dich keine Bücher mit 7 Siegeln sein.

Ein Objekt in einer Funktion

void foo()
{
  Menu c( "test" );
}

existiert auch nur solange, wie diese Funktion läuft. Kehrt die Funktion 
zum Aufrufer zurück, dann wird dieses Objekt zerstört. Daran ändert sich 
auch nichts, wenn du die Adresse dieses Objektes einem anderen Objekt 
zur Aufbewahrung übergibst. Nachdem die Funktion beendet ist, hat dieses 
andere Objekt dann eine Adresse mit der es nichts mehr anfangen kann, 
weil das zur Adresse gehörende Objekt nicht mehr existiert.
Es ist, wie wenn du die Postanschrift eines Freundes hast und wenn du 
dorthin fährst, ist das Haus bereits gesprengt worden. Die Adresse war 
irgendwann mal gültig, jetzt ist sie für dich aber nutzlos.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

>> Ich glaube der constructor functioniert nicht mit new
>
> Doch. Tut er.

Mein Fehler.
In einem gewissen Sinne hast du schon recht.
Das Problem liegt allerdings woanders. Das Problem liegt darin, dass 
sich diese 'Menu' Klasse nicht um die Strings kümmert, sondern einfach 
nur den übergebenen Pointer speichert. Und damit muss man jedem 
Menüpunkt seinen eigenen String geben und kann sich nicht so einfach 
mittels sprintf die Punkte in immer demselben char-Array zusammenbauen. 
Denn dann würden alle derart erzeugten Menüpunkte denselben String 
benutzen.
Und da beginnt die ganze Geschichte jetzt aufwändig zu werden, wenn man 
auf new verzichten möchte. Denn jetzt braucht man auch noch eine 
Stringverwaltung, die sich aus einem großen char-Array entsprechende 
Abschnitte reserviert, die es benutzen kann um darin die Strings 
unterzubringen.

Und damit wird dann dieser Punkt
> Desweiteren würde ich die Menupunkte gerne wie eine array
> also per for-schleife hinzufügen.
zu einem Albtraum. Denn wo kriegst du die Strings her, ohne einen 
Stringpool?

Wenn du damit leben kannst, dass die Strings eine maximale (kleine) 
Länge haben müssen UND es nicht allzuviele Menüpunkte geben soll (damit 
ist gemeint: die Maximalanzahl), dann würde ich einen Redesign der Menu 
Klasse ins Auge fassen, so dass jeder Menüpunkt sein eigenes char-Array 
selbst mit hat und sich nicht einfach nur einen Pointer auf den Text 
speichert.

von Andreas F. (codecasa)


Angehängte Dateien:

Lesenswert?

Okay bin ich am verzweifeln jetzt hängt der avr sich auf wenn ich nach 
dem Seriellen eingang Die Menuinit nochmal ausführe

Muss ich die MenuItems Löschen oder wie
so z.B

Item11 = null;

im Anhang habe ich mal den Code von meinem Projekt

von Andreas F. (codecasa)


Angehängte Dateien:

Lesenswert?

So Jetzt hängt er sich wieder auf:


if(prog)
          {

            *mnuProg[0] = Menu("fdfdgfg");
            Item11.addChild(*mnuProg[0]);

          }

Diese pointer sin mein Horror echt :(

* = Pointer Zeiger
& = Adreesse

Aber pointer ist doch das selber wie Die Adresse oder

Und was ist  der Unterschied Zwichen:

 Menu* mnuProg[99];
und
 Menu *mnuProg[99];

????

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:
> So Jetzt hängt er sich wieder auf:
>
>
> if(prog)
>           {
>
>             *mnuProg[0] = Menu("fdfdgfg");
>             Item11.addChild(*mnuProg[0]);
>
>           }

In deinem Code gibt es kein mnuProg

Ausserdem ist das

   Menu("fdfdgfg");

schon wieder ein temporäres Objekt. Mit der schliessenden } wird es 
zerstört.


> Und was ist  der Unterschied Zwichen:
>
>  Menu* mnuProg[99];
> und
>  Menu *mnuProg[99];

keiner.



Hab ich euch eigentlich schon mal von meiner Theorie erzählt, nach der 
die Programmierer mit dem scheuslichsten Sourcecode auch meistens die 
mit den seltsamsten Fehlern sind?

von Andreas F. (codecasa)


Lesenswert?

> In deinem Code gibt es kein mnuProg
>

Jetzt aber schon mnuProg[99];
:)



> Ausserdem ist das
>
>    Menu("fdfdgfg");
>
> schon wieder ein temporäres Objekt. Mit der schliessenden } wird es
> zerstört.

Ja Klar ich übergebe es aber mit:
*mnuProg[0] = Menu("fdfdgfg");


> Hab ich euch eigentlich schon mal von meiner Theorie erzählt, nach der
> die Programmierer mit dem scheuslichsten Sourcecode auch meistens die
> mit den seltsamsten Fehlern sind?

eso es - Ich bekomme diese zeiger einfach nicht in den Kopf

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:

> Ja Klar ich übergebe es aber mit:
> *mnuProg[0] = Menu("fdfdgfg");

Dazu müsste man die Deklaration von mnuProg sehen.

Wenn du die so hast

Menu* mnuProg[99];

dann übergibst du nichts. Ganz im Gegenteil, du bügelst dir gerade 
deinen Speicher nieder.

Ein Pointer alleine hilft dir nichts! Der muss auch irgendwo hinzeigen! 
Wo ist denn das Objekt auf welches mnuProg[0] zeigt? und welches mit dem 
Inhalt des temporären Objektes überschrieben werden soll?


Daher: den echten Code zeigen! Wie soll ich rausfinden was bei deiner 
Poitnerverwendung falsch ist, wenn du den Code nicht herzeigst?

Das wichtigste bei Pointern ist:
Mit einem Pointer alleine hast du noch kein Objekt! Du hast eine 
Pointervariable, ja. Aber die muss erst mal auf ein Objekt zeigen.

Das ist wie in der Biobliothek. Ein Pointer ist nichts anderes als ein 
Zettel (im Zenttralregister), auf dem steht: Das echte Buch steht im 
Gang A, Regal 4, 3. Buch von links.
Der Zettel ist aber nicht das Buch! Der Zettel sagt mir nur, wo ich das 
Buch finden kann. Das Buch muss seperat zum Zettel existieren. Und nur 
weil ich auf einen Zettel draufschreibe: "Dresdner Codes, Gang B, Regal 
5", heißt das noch lange nicht, dass ich auch wirklich das Buch 
"Dresdner Codex" in meiner Bibliothek habe.

von Andreas F. (codecasa)


Angehängte Dateien:

Lesenswert?

So hier hanz frisch im Anhang:

von Andreas F. (codecasa)


Lesenswert?

Ahhh stimmt ich muss Die Array initialisieren


Alo kann ich das so machen ?

Menu mnuProg[99];
Menu *mnuProg[99];







void plapla()
{

            Menu tmpMenu("hhahaha");
            mnuProg[1] = &tmpMenu;
            Item11.addChild(*mnuProg[1]);
}

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:

> Alo kann ich das so machen ?
>
> Menu mnuProg[99];
> Menu *mnuProg[99];

Kannst du.
Wobei sich die Frage erhebt, wozu du dann das Pointer Array noch 
brauchst.

von Karl H. (kbuchegg)


Lesenswert?

Disclaimer:

> void plapla()
> {
>            Menu tmpMenu("hhahaha");
>           mnuProg[1] = &tmpMenu;
>           Item11.addChild(*mnuProg[1]);

Nein. Kannst du nicht.
mnuProg[1] enthält einen Zeiger auf tmpMenu. tmpMenu existiert aber 
nicht mehr, nachdem plapla verlassen wird.
Ergo: Item11.addChild hat sich schon wieder eine Adresse gemerkt, die 
auf ein Objekt verweist, welches nach verlassen der FUnktion nicht mehr 
existiert.

von Andreas F. (codecasa)


Lesenswert?

Nein geht nicht:

Ich bekomme Folgenden Fehler:

impulse_cleaner_01.cpp:145:20: error: no matching function for call to 
‘Menu::Menu()’
/usr/share/arduino/libraries/Menu/Menu.h:27:2: note: candidates are: 
Menu::Menu(char*, boolean (*)(Menu&))
/usr/share/arduino/libraries/Menu/Menu.h:26:2: note: 
Menu::Menu(char*)
/usr/share/arduino/libraries/Menu/Menu.h:14:1: note: 
Menu::Menu(const Menu&)
impulse_cleaner_01.cpp:146:21: error: conflicting declaration ‘Menu* 
mnuProg [99]’
impulse_cleaner_01.cpp:145:20: error: ‘mnuProg’ has a previous 
declaration as ‘Menu mnuProg [99]’
impulse_cleaner_01.cpp: In function ‘void menuinit(boolean)’:
impulse_cleaner_01.cpp:200:27: error: no match for ‘operator=’ in 
‘mnuProg[1] = & tmpMenu’
/usr/share/arduino/libraries/Menu/Menu.h:14:1: note: candidate is: Menu& 
Menu::operator=(const Menu&)
impulse_cleaner_01.cpp:201:39: error: no match for ‘operator*’ in 
‘*mnuProg[1]’

von Karl H. (kbuchegg)


Lesenswert?

1
Menu    mnuProg[99];
2
uint8_t usedMnu = 0;
3
4
Menu* allocateMenu()
5
{
6
  if( usedMnu >= 99 )   // gibt es noch unbenutzte Einträge im Array?
7
    return NULL;        // nein, leider nicht. Alles bereits im Einsatz
8
9
                        // ja, da ist noch einer.
10
                        // seine Adresse liefern und im Zähler vermerken
11
                        // dass jetzt eines mehr benutzt ist
12
  return &mnuProg[usedMnu++];
13
}
14
15
void plapla()
16
{
17
  Menu* newMenu = allocateMenu();
18
19
  if( newMenu == NULL )   // da ist wohl was schief gelaufen
20
    return;
21
22
  newMenu.name = "fdfdfd";
23
  Item11.addChild( newMenu );
24
}

Aber Achtung: Die Sache mit dem String ist deswegen noch lange nicht aus 
der Welt! Das geht hier nur deshalb, weil "fdfdfd" ein String-Literal 
ist.

von Andreas F. (codecasa)


Lesenswert?

Der will bei der Initialisierung einen pointer zu einem char übergeben 
haben ;)

Mein Kopf Brummt gleich :(

von Karl H. (kbuchegg)


Lesenswert?

> impulse_cleaner_01.cpp:145:20: error: no matching function for call to
‘Menu::Menu()’


Du hast keinen Default-Construktor.
Also einen der dann benutzt werden kann, wenn man ein Menu Objekt 
erzeugen will, ohne Argumente


Es hilft alles nichts.
Du brauchst ein C++ Buch. Und zwar dringend. C ist schon ohne LIteratur 
nicht zu erlernen. Und für C++ gilt das noch viel mehr.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:
> Der will bei der Initialisierung einen pointer zu einem char übergeben
> haben ;)

Was DER WILL ist eine Sache, die ja nicht in Stein gemeisselt ist. Wer 
oder was hindert dich daran, dir einen Konstruktur zu schreiben, der 
eben genau das NICHT haben will.

Richtig: Niemand.

von Andreas F. (codecasa)


Lesenswert?

impulse_cleaner_01.cpp:145:23: error: no matching function for call to 
‘Menu::Menu()’
/usr/share/arduino/libraries/Menu/Menu.h:27:2: note: candidates are: 
Menu::Menu(char*, boolean (*)(Menu&))
/usr/share/arduino/libraries/Menu/Menu.h:26:2: note: 
Menu::Menu(char*)
/usr/share/arduino/libraries/Menu/Menu.h:14:1: note: 
Menu::Menu(const Menu&)

von Andreas F. (codecasa)


Lesenswert?

ja stimmt danke

von Andreas F. (codecasa)


Lesenswert?

impulse_cleaner_01.cpp: In function ‘void pal()’:
impulse_cleaner_01.cpp:214:11: error: request for member ‘name’ in 
‘newMenu’, which is of non-class type ‘Menu*’
impulse_cleaner_01.cpp:215:28: error: no matching function for call to 
‘Menu::addChild(Menu*&)’
/usr/share/arduino/libraries/Menu/Menu.h:29:7: note: candidate is: void 
Menu::addChild(Menu&)
impulse_cleaner_01.cpp: In function ‘void menuinit(boolean)’:
impulse_cleaner_01.cpp:225:17: error: ‘pla’ was not declared in this 
scope

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:
> impulse_cleaner_01.cpp: In function ‘void pal()’:
> impulse_cleaner_01.cpp:214:11: error: request for member ‘name’ in
> ‘newMenu’, which is of non-class type ‘Menu*’


Was sagt uns diese Fehlermeldung?

Da ist von einem newMenu die Rede. Soweit so gut. Was ist damit?

> which is of non-class type ‘Menu*’

Aha. newMenu ist keine Klasse, sondern vom Datentyp Menu*. Also 
offensichtlich ein Pointer.

> request for member ‘name’ in ‘newMenu’

und von diesem Pointer wollte ich auf den Member 'name' zugreifen.

Das kann nicht gehen. Da hat der Compiler völlig recht. Ein Pointer hat 
keine Member. Höchstens das worauf er zeigt.

  newMenu.name

kann daher nicht richtig sein. Es muss

  newMenu->name

heissen.

von Karl H. (kbuchegg)


Lesenswert?

> no matching function for call to ‘Menu::addChild(Menu*&)’

Was sagt uns diese Fehlermeldung?
Wie findest du raus, was da faul ist?


Es gibt zwar Fehlermeldungen, die missverständlich sind, aber die 
meisten geben ganz gute Hinweise darauf, wo das Problem liegt. Du musst 
sie nur lesen, den Text auseinandernehmen ("Wovon ist die Rede", 
"Worüber beschwert sich die 'Maschine' Compiler), den geschriebenen Code 
ansehen und mit der Fehlermeldung abgleichen. Dann kriegt man die Fehler 
auch raus.

Aber nicht einfach nur bei Code, den ich direkt hier eintippe (und bei 
dem ich klarerweise auch Fehler mache), einfach nur die Fehlermeldung 
nehmen, Cut&Paste hier einkopieren und auf Antwort warten.

Fehlermeldungen lesen und interpretieren können, ist genauso eine 
wichtige Fähigkeit, wie das Schreiben von Code. Manchmal muss man ein 
wenig um die Ecke denken aber oft ergibt sich das Problem mehr oder 
weniger direkt aus der Fehlermeldung.

von Andreas F. (codecasa)


Lesenswert?

Klarr das problem ist nur das Die Blöde Arduino IDE nicht die richtigen 
Zeilen im Code anzeigt.


Reinkopieren ;) g


Hier habe ich auch ein fehler endeckt:
void pal()
{
  Menu* newMenu = allocateMenu();

  if( newMenu == NULL )   // da ist wohl was schief gelaufen
    return;

  char tStr = 'fdfdfd';
  newMenu->name = "Hallo";

  Item11.addChild( newMenu); / <-- hier fehlt * vor dem new Menu ;)
}

Jetzt geht es endlich nur wenn ich oben
Menu    mnuProg[99]; so stehen lasse Bleibt das Display an und er hängt


bei Menu    mnuProg[9]; geht es

Ist der Speicher schon aufgebraucht ich muss dazu sagen das ich auch 
noch an Maneu.h und Manu.cpp was abgeändert habe

cpp:
+Menu::Menu()
+{
+name=NULL;
+canEnter=NULL;
+}

+void Menu::setName(char *n)
+{
+  name=n;
+}

Header-Datei:
Die Declaratione für die cpp



War das gut ?

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:

>   Item11.addChild( newMenu); / <-- hier fehlt * vor dem new Menu ;)

Korrekt

> Jetzt geht es endlich nur wenn ich oben
> Menu    mnuProg[99]; so stehen lasse Bleibt das Display an und er hängt
>
>
> bei Menu    mnuProg[9]; geht es
>
> Ist der Speicher schon aufgebraucht

Sieht wohl so aus.
Wievel SRAM hast du denn zur Verfügung und wieviel davon ist schon von 
anderen Dingen aufgebraucht?

Arbeitet man mit dem AVR-gcc im AVR Studio, dann kriegt man am Ende eine 
Statistik, der man entnehmen kann, wie eng man schon an den 
physikalischen Grenzen liegt. Gibts sowas auch in der Arduino-IDE?

> cpp:
> +Menu::Menu()
> +{
> +name=NULL;
> +canEnter=NULL;
> +}
>
> +void Menu::setName(char *n)
> +{
> +  name=n;
> +}
>
> War das gut ?

Ja, das war gut.

von Andreas F. (codecasa)


Lesenswert?

Na toll ich muss denn contreoller fetig bekommen


Nein Die IDE von Arduino ist niemandem zu empfehlen !
Ich will praktisch Programme Laden und diese apblaufprogramme auch im 
Menü Job1 z.B anzeigenlassen.

Aber ich kann mir nicht vorstellen das das so schnell zu ende ist


Vieleicht sollte ich das anderster lösen weil ich ja nur feste Befehle 
habe wie. z.b


start_imp(1500,500);
oder
end;
oder;
pmp(an);

von Karl H. (kbuchegg)


Lesenswert?

Andreas Frauenstein schrieb:

> Vieleicht sollte ich das anderster lösen weil ich ja nur feste Befehle
> habe wie. z.b

Ich würds so lösen, dass ich im Controller maximal 10(hausnummer) 
benutzerdefinierte Programme ablegen kann. Für diese 10 Programme machst 
du die Menüpunkte fix rein und erweiterst ev. die Menüpunkte noch mit 
einer 'ist aktiv/nicht aktiv' Steuerung. Genauso wie es auch Windows 
macht, wenn einzelne Menüpunkte ausgegraut sind.

Lass dich von der Prämisse leiten: In der µC Programmierung, auf den 
kleinen µC, sind fixe Zahlen bzw. Obergrenzen immer das
a) einfachste
b) beste

'Einfach' deswegen, weil du als Programmierer dann fixe Größen hast, mit 
denen du hantieren kannst.
'Beste' deswegen, weil der Benutzer dann weiß, woran er ist. Hier weiß 
er: 10 Programme und dann ist Schluss. Damit kann er arbeiten. Und das 
ist immer noch besser, als wenn er sich großartig was ausdenkt, das dann 
versucht upzuloaden (grausliches Wort) und einen 'Out of memory' Fehler 
bekommt.


PS: Neben der Menüsteuerung musst du ja auch noch die 'Programme' selbst 
im Speicher verwalten. Das wird schon wieder was dynamisches und da 
kommst du gefühlsmässig um die Dynamik überhaupt nicht rum.
Langsam wirds eng im Speicher.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.