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.
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 ;-)
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
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.
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.
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.
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
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]; ????
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?
> 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
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.
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]); }
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.
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.
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]’
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.
Der will bei der Initialisierung einen pointer zu einem char übergeben haben ;) Mein Kopf Brummt gleich :(
> 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.
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.
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&)
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
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.
> 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.
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 ?
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.
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);
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.