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
charstr[6];
3
4
for(inti=0;i<3;i++){
5
sprintf(str,"Test%d\0",i+1);
6
tmpMENU[i]=newMenu(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]’
> 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: 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.