Hallo, ich versuche mir gerade ein Menü zu erstellen, davor will ich
aber diesen Code verstehen lernen, ich komme besten willen nicht darauf
für was der Pointer *menu_strings[MENU_ITEMS] gedacht ist ?
Gruß
#define MENU_ITEMS 4
char *menu_strings[MENU_ITEMS] = { "First Line", "Second Item",
"3333333", "abcdefg" };
uint8_t menu_current = 0;
uint8_t menu_redraw_required = 0;
uint8_t last_key_code = KEY_NONE;
void drawMenu(void) {
uint8_t i, h;
u8g_uint_t w, d;
u8g.setFont(u8g_font_6x13);
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent()-u8g.getFontDescent();
w = u8g.getWidth();
for( i = 0; i < MENU_ITEMS; i++ ) {
d = (w-u8g.getStrWidth(menu_strings[i]))/2;
u8g.setDefaultForegroundColor();
if ( i == menu_current ) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(d, i*h, menu_strings[i]);
}
}
void updateMenu(void) {
if ( uiKeyCode != KEY_NONE && last_key_code == uiKeyCode ) {
return;
}
last_key_code = uiKeyCode;
switch ( uiKeyCode ) {
case KEY_NEXT:
menu_current++;
if ( menu_current >= MENU_ITEMS )
menu_current = 0;
menu_redraw_required = 1;
break;
case KEY_PREV:
if ( menu_current == 0 )
menu_current = MENU_ITEMS;
menu_current--;
menu_redraw_required = 1;
break;
}
}
void setup() {
// rotate screen, if required
// u8g.setRot180();
uiSetup(); // setup key detection and
debounce algorithm
menu_redraw_required = 1; // force initial redraw
}
void loop() {
uiStep(); // check for key press
if ( menu_redraw_required != 0 ) {
u8g.firstPage();
do {
drawMenu();
} while( u8g.nextPage() );
menu_redraw_required = 0;
}
updateMenu(); // update menu bar
}
D. Chung schrieb: > ich komme besten willen nicht darauf > für was der Pointer *menu_strings[MENU_ITEMS] Das ist nicht ein Pointer, das ist ein Array aus Pointern.
Gast
#3771810
Wie Rufus schon sagte ist menu_strings ein Array von Pointern. Genauer ein Array von char Pointer und ein char Pointer ist quasi ein string. In dem von dir gezeigten Code werden hier die verschiedenen Menüeinträge abgespeichert.
Ja wenn ich noch dabei bin hab ich mich falsch ausgedrückt, aber warum das ganze ?Wie Pointer funktionieren das versteh ich,...Vill könntest du mir das erklären wieso ? Gruß
Gast
#3771821
Um das Ganze möglichst flexibel zu gestalten. Kein Mensch will die Menüeinträge wild verteilt in den Code werfen und Konstruktion wie
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
bauen. Bis aus den anzuzeigenden Text ist der Code zum Menüträge anzeigen offensichtlich identisch. Also packt man alle Einträge in ein Array und arbeitet dies ab.
Danke für die schnellen Antworten, ja das mit dem Array ist mir ja klar
aber mich stört der Stern ... es würde doch auch ohne Pointer gehen. Ich
erkenne den Sinn dahinter nicht in diesem Beispiel, das ist mein Problem
würde jetzt
menu_strings[MENU_ITEMS] = { "First Line", "Second Item",...
dort stehen müsste es doch auch funktionieren ?
Gast
#3771840
D. Chung schrieb: > Danke für die schnellen Antworten, ja das mit dem Array ist mir ja klar > aber mich stört der Stern ... es würde doch auch ohne Pointer gehen. Ich > erkenne den Sinn dahinter nicht in diesem Beispiel, das ist mein Problem > > würde jetzt > > menu_strings[MENU_ITEMS] = { "First Line", "Second Item",... > > dort stehen müsste es doch auch funktionieren ? Nein. Das würde der Compiler mit einer Fehlermeldung wegen eines fehlenden Datentyps quittieren. Schriebst Du jetzt, aber: char menu_strings[MENU_ITEMS] = { "First Line", "Second Item",... so erhälst Du damit ein Array, das nur aus einem MENU_ITEMS langem String besteht, versuchst aber das Array mit mehreren Strings zu initialisieren. Nimm's mir bitte nicht übel, aber das ist das Paradebeispiel für eine Gelegenheit, auf C-Bücher zu verweisen.
Gast
#3771843
Erstmal geht menu_strings[MENU_ITEMS] alleine sowieso nicht. Da fehlt noch der Typ, also wenn dann char menu_strings[MENU_ITEMS]. Und nein so funktioniert das nicht. Wenn du das so machst hast du ein Array in dem du MENU_ITEMS chars also einzelne Zeichen speichern möchtest. Tatsächlich möchtest du aber MENU_ITEMS strings in dem Array Speichern. Hier noch einige Beispiele zu strings:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Ja der Datentyp muss natürlich dabei sein.
@Bitflüsterer
Ich glaub langsam komme ich dahinter bzw. hab wohl was übersehene
char menu_strings[] = { "First Line", "Second Item"}
würde doch ein Array aus 2 char s bilden.
char menu_strings[1]-> First Line
char menu_strings[2]-> Second Item
Würde eine Zahl darin stehen wie
char menu_strings[2] = { "First Line", "Second Item"}
würde das heißen das in menu_strings[2] -> "First Line", "Second Item"
drin stehen würde ?
Und bei
#define MENU_ITEMS 4
char *menu_strings[MENU_ITEMS] = { "First Line", "Second Item",
"3333333", "abcdefg" };
Steht in
char *menu_strings[1] -> First Line
char *menu_strings[2] -> Second Item
char *menu_strings[3] -> 3333333
char *menu_strings[4] -> abcdefg
Ich hoffe ich bin auf dem richtigen Pferd ?
Gast
#3771859
> Ich hoffe ich bin auf dem richtigen Pferd ?
Nein. Durchaus nicht. Bitte lies ein C-Buch. :-)
Gast
#3771860
Ich glaube du brauchst tatsächlich ein gutes C Buch...
Wenn du ein Array definierst besagt die Zahl in den eckigen Klammern wie
viele Elemente dein Array haben soll. Man kann die Zahl auch weglassen
dann kriegt das Array so viele Elemente wie du in den runden {} Klammern
liefest. Wenn du später auf das Array zugreifst dann gibst du in den
eckigen Klammern an auf welches Element zu zugreifen willst. Die Zählung
beginnt auch bei 0 und nicht bei 1 wie in deinem Beispiel oben.
sebi707 schrieb: > Ich glaube du brauchst tatsächlich ein gutes C Buch... > > Wenn du ein Array definierst besagt die Zahl in den eckigen Klammern wie > viele Elemente dein Array haben soll. Man kann die Zahl auch weglassen > dann kriegt das Array so viele Elemente wie du in den runden {} Klammern > liefest. Wenn du später auf das Array zugreifst dann gibst du in den > eckigen Klammern an auf welches Element zu zugreifen willst. Die Zählung > beginnt auch bei 0 und nicht bei 1 wie in deinem Beispiel oben. Sebi707 @ Hä das selbe hab ich doch gerade gemeint ? Bis auf das mit der 0. Beispiel char a=menu_strings[1] in a steht dann Second Item?
Gast
#3771867
Nein. In einem char kannst du keinen kompletten String speichern. Du brauchst entweder ein Array oder einen Pointern. So muss das aussehen: char* a=menu_strings[1]; Dann steht da drin "Second Item".
D. Chung schrieb: > char a=menu_strings[1] > > in a steht dann Second Item? Nein. Ein char ist ein einzelnes Zeichen.
sebi707 schrieb: > Nein. In einem char kannst du keinen kompletten String speichern. Du > brauchst entweder ein Array oder einen Pointern. So muss das aussehen: > char* a=menu_strings[1]; > > Dann steht da drin "Second Item". Weil ein char 8 bit lange ist... Sollte ich eigentlich wissen, bin schon zulange davon weg sry.
Das hier
1 | |
baut im Speicher diese Struktur auf
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Ein Array von Pointern unter dem Namen menu_strings, wobei jeder einzelne der Pointer auf einen Text zeigt. Man hätte natürlich auch ein 2D Array von chars machen können
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
das hat aber den 'Nachteil', das alle 'Zeilen' des 2D Arrays gleich lang sein müssen. Was wiederrum Speicherverschwendung bedeutet, wenn gleichzeitig relativ lange und relativ kurze Texte in diesem Array gespeichert werden sollen. Denn die Anzahl der Spalten ist ja über das komplette 2D Array in allen Zeilen gleich und muss sich logischerweise am längsten zu speichernden Text orientieren. In der Lösung mit dem Pointer Array brauch ich das nicht. Die Texte sind ja unabhängig vom Array. Das Array organisiert die nur insofern, dass es die Verweise enthält, wo die tatsächlichen Texte gespeichert sind. Und die können unabhängig voneinander beliebig lang sein.
Okay danke, das leuchtet ein. Jetzt wenn ich dieses Thema weiter ausbauen will und noch Sub Menü s erzeugen will hätte ich anfangs das Array um eine Dimension erweitert, dann war mein Gedanke dazu das ich Plätze im Array verschwende, weil ich unterschiedliche Sub menues evtl habe... Meine zweite Lösung besteht aus mehreren Switch case bzw genau der Anzahl der main menues, damit wäre ich in der Anzahl der unter Menues variable. Das wird aber irgendwann unübersichtlich denk ich. Jetzt könnte ich mir das auch mit Pointer vorstellen, das wäre die elegantere Lösung oder ?Das wäre dann doch eine Pointer auf Pointer Struktur ? Gruß
Der ganze Ansatz ist schon zweifelhaft. Denn ein Menü besteht ja nicht
nur aus Texten. Spätestens wenn du noch Submenüs haben willst und ev.
sogar direkt Funktionen an Menüpunkte hängen willst, solltest du mal ein
gutes C Buch konsultieren, welche Möglichkeiten zur Datenstrukturierung
du noch hast. Ein Array ist beileibe nicht alles, was dir an
Möglichkeiten zur Verfügung steht. Da gibt es zb noch die Struktur.
> Das wird aber irgendwann unübersichtlich denk ich.
Im Idealfall hast du EINEN Code, der ein Menü in all seinen Ausprägungen
behandeln kann. Die Daten steuern die Menüabaerbeitung. Der Code
interpretiert nur die Daten in der aufgebauten Datenstruktur. So ein
Design beginnt damit, dass man sich auf Papier mit Bleistift die
Datenstruktur anhand eines konkreten Beispiels aufmalt. Dann sieht man
schon, wie man das ganze strukturiert.
Aber wenn dir das Pointer Array schon kopfzerbrechen bereitet hat,
solltest du dir vielleicht erst mal die Latte nicht so hoch legen, bis
du deine Programmiersprache nicht nur rudimentär beherrscht sondern
tatsächlich mit den Sprachmitteln auch umgehen kannst.
Gast
#3771964
@KHB Danke für die tolle Darstellung. Wie biegen sich die Zeiger, wenn ich keinen linearen Speicher, sondern RAM und ROM getrennt mit gleichem Adressbereich habe?
embedded schrieb: > @KHB > Danke für die tolle Darstellung. Wie biegen sich die Zeiger, wenn ich > keinen linearen Speicher, sondern RAM und ROM getrennt mit gleichem > Adressbereich habe? Im Prinzip genau gleich. Denn in der Darstellung ist das ja uninteressant. Du musst nur im Hinterkopf behalten was in welchem Speicher liegt (kann nicht schaden, wenn man sich das in der Zeichnung markiert) und je nach Compiler dann eben die entpsrechende Umsetzung in den C Code machen. Je nach Compiler ist das unterschiedlich. Bei manchen kommt dann eben zb ein 'const' in die Datenstruktur rein, bei anderen wieder gibt es spezielle Zugriffsfunktionen für zb den ROM Bereich. Aber grundsätzlich fürs Design ist das erst mal recht uninteressant. In der Zeichnung ist ein Pointer nichts anderes als ein Pfeil, der in einem Kästchen anfängt und dessen Spitze irgendwo anders hinzeigt.
Ich hab mir mal Gedanken dazu gemacht, ich denke der Ansatz wäre sehr
einfach bezüglich weil ich in einem späteren Switch case die id abfragen
kann sollte man zb. in dieser Menü Ebene was abfragen wollen.
Strukturen kenne ich noch, das wird aber jetzt eine Struktur der sich
wohl ein Array befinden muss
struct menu{
const char* Menu_name; // Menue Name
int id; // Menue ID,damit ich mich orientieren
kann
int Number; // Anzahl der Submenues
{
"Submenue 1, id" //Name des Submenues mit der ID
"Submenue ....
......
}
}
}
Das Array würde dann so aussehen
menuEntry []={Submenue 1, id}
Jetzt stellt sich mir aber die Frage wie mache ich die Anzahl der Array
s variable ich habe ja unterschiedlich viele Sub menues
menuSet []={SubSet_1, id}
menueHome []={SubSet_2, id}
....
Wäre der Ansatz okay ? Ich weiß nur gerade einfach nicht wie ich mit dem
Array umgehen muss...
Gruß
Zum Array wäre mir noch was eingefallen, ich verpacke die arrays wieder
in eine Struktur , dann wäre die Anzahl doch variable ?
struct menu{
const char* Menu_name; // Menue Name
int id; // Menue ID,damit ich mich orientieren kann
int Number; // Anzahl der Submenues
struct Sub_menue[]; //
}
}
Und dann habe ich eine Struct in dem sich die Arrays finden mit zb dem
Namen und wieder der ID
Damit hätte ich auch alle Parameter mitgeliefert die ich für ein Menü
brauche
-Anzahl Submenues damit ich Anfang und Ende kenne.
-Id damit ich den Menue abschnitte kenne
-Und den Namen zur ausgabe am Display.
Ich hab das mal runter getippt.
void Menues(void){
struct menu{
const char* Menu_name; // Menue Name
int id; // Menue ID , damit ich mich orientieren
kann
int Number; // Anzahl der Submenues
strukt Sub_menue [];
}
struct menue Main =
{
"Main",
10,
2,
{
{"Info", 100},
{"back", 90},
}
};
struct menu Data_Log =
{
"Data Log",
20,
4,
{
{"Start", 200},
{"Stop", 201},
{"Settings", 202},
{"back", 203},
}
};
Danke schon mals
Gast
#3773426
Was soll "strukt Sub_menue [];" sein? Da fehlt irgendwie ein Variablenname oder der Typ (je nachdem was Sub_menue sein soll). Außerdem ist struct falsch geschrieben. Compilierst du deinen Code gar nicht zwischendurch? Hast du mitlerweile das C Buch von Anfang bis Ende gelesen und bist jetzt C-Meister und möchtest unbedingt flexible array member benutzen? Wenn nicht dann überleg dir bitte eine andere Speichermöglichkeit, die ohne unterschiedlich große Arays in structs auskommt. Z.B. irgendwas mit Pointern.
Danke nett für deine Antwort, besonders nett der Hinweis das ich mich bei einem pseudo Code vertippt habe. Es gibt auch noch Anfänger hier das sollte man nicht vergessen, zu dem sieht man bei mir das ich mir nicht die Arbeit machen lasse und selbst mit Ideen komme. C und C++ ist bei mir einfach auch schon mal wieder lange her!!! Man kann sich auch anständig unterhalten oder ? Und zum strukt Sub_menue []; alias struct Sub_menue []; ja zu diesem Datentyp bin ich mir nicht wirklich sicher , zumal ich mir die Frage stelle ob das möglich ist. Mit Stukturen zu arbeiten wäre mir auf anhieb einleuchtend, ich lass mich aber gern eines besseren belehren,.. Gruß
Gast
#3774539
Der Grund warum hier mehrere zu einem C Buch raten ist, dass du offensichtlich Defizite bei wichtigen Themen wie z.B. Pointern hast. Viele deiner Antworten sind irgendwie hingeschriebener C Code oder wie du ja jetzt sagst Pseudo-Code. Ohne richtiges Verständnis welche Konstruktionen es in C gibt und welche nicht kommt man meistens nicht weit. In Pseudo-Code kann man theoretisch alles hinschreiben, aber ob das in C dann so umzusetzen ist, ist noch eine ganz andere Frage. Wenn ich mir ein Design überlege dann schreibe ich das direkt in der Programmiersprache hin, in der ich es auch umsetzen möchte und sehe dann spätestens beim Compilieren ob das so überhaupt funktioniert. Um auf dein eigentliches Problem zurückzukommen: Du möchtest eine Menüstruktur mit Funktionen für einzelne Menüpunkte, sowie Untermenüs darstellen. Das Ganze soll auf einem µC laufen? Hast du nirgendwo erwähnt scheinbar. Arrays mit variabler Länge in structs gibt es zwar in C, ist aber eher ein spezial Feature und sollte man nicht unbedingt verwenden, da es immer anders geht. Der ursprüngliche Ansatz mit einem Array von char* war gar nicht so schlecht. Wenn man statt char* ein struct für ein Menüeintrag erstellt kommt man schon weiter. Ich habe mir jetzt in ein paar Minuten mal diese Struktur überlegt:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
Ein Menüeintrag besteht aus einem Namen, einem Functionpointer (bitte Nachlesen wenn dir das nichts sagt), sowie einem Pointer auf ein Untermenü. Falls beim Auswählen eines Menüpunktes eine Funktion aufgerufen werden soll trägst du die Funktion in den Functionpointer ein. Versteckt sich hinter einem Menüeintrag ein Untermenü dann trägst du den submenu Pointer ein. Die einzelnen Menüs werden dann wieder in Arrays gespeichert, mit einem abschließenden Menüeintrag, der nur aus NULL Einträgen besteht. Der NULL Eintrag markiert das Ende eines Menüs. Dadurch kann man einfach auf ein Untermenü verweisen und muss nicht auch noch die Länge irgendwo mitgeben.
Bin gerade unterwegs und danke für deine Antwort, ich hab das ganze
jetzt schnell überflogen.
Ganz kurz aber noch-->
MenuItem mainMenu[] = {
{"First function", &func1, NULL},
{"Submenu", NULL, submenu},
{"Second function", &func2, NULL},
{NULL, NULL, NULL}
};
Main Menue ist ja der oberste Menuepunkt, bei den Submenues was wäre für
dich jetzt eine First function und eine Second funktion?
Wenn ich die Hierarchie richtig verstanden habe
dann würde das in meinem Fall so aussehen -->
MenuItem mainMenu[] = {
{""Main"",Submenue_menue, NULL},
{"Data Log",Submenue_Datalog, Null},
{"Diagnostic",Submenue Diagnistic, NULL},
{NULL, NULL, NULL}
};
MenuItem Submenue_Datalog[] = {
{""Sub1",Sub11,&func0 },
{" Sub2",Sub12,&func1},
{" Sub3",Sub13,&func2},
{NULL, NULL, NULL}
}
Ich versuch das jetzt mal umzusetzen, klingt alles noch logisch danke.
Gruß
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.