Tach zusammen! Hab da ein Problem bei der Realisierung meiner Menüstruktur in C. Ich habe vier Taster zur Bedienung meiner Menüstruktur. Ich habe ein Grundmenü was sich wiederrum in mehrere Untermenüs aufsplittet. Kann ich diese Menüführung nur über eine if Anweisung mit einer while Schleife aufbauen oder weiß jemand von Euch einen besseren Rat? Bin dankbar für jeden Ratschlag!
Deine Frage ist in etwa so präzise wie "Ich möchte ein großes Haus bauen. Wie viele Fenster brauch ich?"
Natürlich kannst du das, du speicherst in einer Variable den Tastencode (0-3) und wertest dann mit Hilfe von "switch" - "case" das ganze aus. if geht auch; ich persönlich finde switch case schöner. Zumindest wenn mehr als ein Befehl ausgeführt werden soll.
...ja, oder eine funktion für alles, der über gibst du dann eine liste von funktionspointern.. gruß, whitenoise
Ich wäre für switch! für jede Auswahlmöglichkeit(zb. im Hauptmenü sind 6 untermenüs aufrufbar) eine switch-Anweisung nutzen. Im Untermenü dann wieder ein switch switch(hautpmenü) switch(untermenü1) . . . ich weiß, das mit den üs geht so net, also nicht auf mir rumhacken... ;)
Dazu hab ich mir irgendwann mal folgendes zusammenprogrammiert:
1 | // menu entry structure
|
2 | struct UImenuEntry |
3 | {
|
4 | const char* name; // entry name |
5 | int id; // entry ID |
6 | };
|
7 | |
8 | |
9 | // simple menu structure
|
10 | struct UImenu |
11 | {
|
12 | const char* menuName; // menu name |
13 | int mid; // menu ID |
14 | |
15 | char entries; // entry count |
16 | struct UImenuEntry e[]; // entries |
17 | };
|
Im Einsatz sieht das dann so aus:
1 | // menus
|
2 | |
3 | struct UImenu menuMain = |
4 | {
|
5 | "Main Menu", // menu name |
6 | 100, // menu id |
7 | 5, // number of entries |
8 | {
|
9 | {"set OCR2", 1000}, // entries |
10 | {"set preOn", 1001}, |
11 | {"set On", 1002}, |
12 | {"set postOn", 1003}, |
13 | {"submenu", 101}, |
14 | }
|
15 | };
|
16 | |
17 | |
18 | struct UImenu menuSub1 = |
19 | {
|
20 | "Sub Menu", |
21 | 101, |
22 | 2, |
23 | {
|
24 | {"Test 4", 1010}, |
25 | {"back", 100} |
26 | }
|
27 | };
|
28 | |
29 | struct UImenu *menuList[]={&menuMain, &menuSub1, NULL}; |
30 | |
31 | |
32 | [...]
|
33 | |
34 | while(1) |
35 | {
|
36 | // enter menu
|
37 | int ret=UImenuExec(); |
38 | |
39 | switch(ret) |
40 | {
|
41 | //
|
42 | // Main Menu
|
43 | //
|
44 | |
45 | case 1000: UIchgInt("set OCR2", setOCR2, getOCR2); |
46 | break; |
47 | |
48 | case 1001: |
49 | UIchgIntPtr("set preOn", &delayPreOn); |
50 | break; |
51 | |
52 | case 1002: |
53 | UIchgIntPtr("set On", &delayOn); |
54 | break; |
55 | |
56 | case 1003: |
57 | UIchgIntPtr("set postOn", &delayPostOn); |
58 | break; |
59 | |
60 | //
|
61 | // Submenu 1
|
62 | //
|
63 | |
64 | case 1010: |
65 | // tuwas
|
66 | break; |
67 | |
68 | }
|
69 | }
|
70 | }
|
UImenuExec zeigt das menu an und gibt eine dem ausgewählten Eintrag entspr. ID zurück (Eintrag anwählen und irgend'n festgelegten button drücken). UIchgIntPtr ist eine Subroutine in der man Werte eingeben kann (mit 4 Tasten). In 64k IDs ist auch genug Platz die Menu IDs unterzubringen, so funktionieren auch submenus ohne das UImenuExec was zurückgibt.
Ich habe mich grade auch mit einem Menü 'rumgeschlagen. Ich rufe zunächst ein Hauptmenü (gesonderte Endlosschleife) auf, in dem kann über swich/case ein Untermenü von 16 gewählt werden (einzelne Funktionen mit enthaltener Endlosschleife). Durch die Displayausgaben, EEPROM lesen/Beschreiben, Werte verändern und begrenzen usw. frisst das Ding ordentlich Speicher. In meinem Regler (mit Sonderfunktionen) frisst das Menü beim mega644 schon 15% des Flash. OK, da kann ich mit leben, aber Optimierung tut da auch Not, werde mich nach Abschluss des Projektes mal dranmachen und in die Codesammlung setzen.
Bei meiner Variante ist die Auswertung recht einfach, ich weis ehrlich gesagt nicht wie man da ~10kB Flash verheizen kann. UImenuExec muss nur folgendes machen: - menu ID von aktuell ausgewähltem menu und Eintragsnummer (pos. in array) in statischer variable speichern - menuList nach passender menu ID für aktuelles Menu durchsuchen (1 Schleife) - Funktion aufrufen die dieses Menu mit aktuell gewähltem Eintrag malt/bei oben/unten Taste die Menueinträge durchgeht, bei ok Nummer des gewählten Eintrags zurückgibt - Gucken ob Menu mit der ID des gewählten Eintrags vorhanden - wenn ja, als neue menu ID benutzen und von vorn anfangen, ansonsten Eintrags-ID zurückgeben Und das war's eigentlich schon.
>ich weis ehrlich gesagt nicht wie man da ~10kB Flash verheizen kann.
Mit der Menüstruktur selbst nicht. Das braucht auch fast nix.
Ich will aber in den einzelnen Untermenüs auch was tun. Bei vielen
Untermenüs (bei mir 16) kommt da schon Code zusammen.
Z.B. einen Bildschirm anzeigen (immer Anders), eine Variable ausgeben,
diese durch Tastendruck hoch, bzw: 'runterzählen, die Variable entweder
im EEPROM abspeichern oder direktes Verlassen des Untermenüs. Die
Tastenabfragen und Absicherungen gegen Überlauf usw. sind in vielen
Untermenüs verschieden, darum kann hier nix zusammengefasst werden.
Das ist wie beim Windoof auch, sobald Benutzereingaben gemacht werden
können müssen Gürtel und Hosenträger her. :)
Das kostet schon Platz. ;)
@ I_ H. Ich versuche gerade deine Menüstruktur nachzubauen. Kannst du auch noch deine "UImenuExec" Funktion posten. Viele Dank!
1 | // current menu and menu list
|
2 | int UImid; |
3 | struct UImenu **UImenuList; |
4 | |
5 | // menu mode - 0 -> 2line display, 1 -> 1line display (lower)
|
6 | char UImode; |
7 | |
8 | // last id and mid, used to point to same
|
9 | // entry on menu recall
|
10 | int UImidLast=-1; |
11 | int UIidLast; |
12 | |
13 | |
14 | |
15 | // menu key masks
|
16 | // #define KEY_UP 0x10
|
17 | // #define KEY_DOWN 0x20
|
18 | // #define KEY_SELECT 0x02
|
19 | |
20 | #define MENU_LINE1 2
|
21 | #define MENU_LINE2 3
|
22 | |
23 | |
24 | |
25 | |
26 | // show menu entry
|
27 | // l -> display line to use
|
28 | // n -> entry number+1; note: 0 means show menu itself
|
29 | // s -> if(s) show entry as selected
|
30 | void UIshowEntry(struct UImenu *menu, char line, char n, char s) |
31 | {
|
32 | char baseLine, i; |
33 | |
34 | // menu sizes
|
35 | const int menuWidth=16; |
36 | |
37 | // selected entry
|
38 | if(line==0) baseLine=MENU_LINE1; |
39 | else baseLine=MENU_LINE2; |
40 | |
41 | // clear display area and goto start
|
42 | // LCDgoto(base);
|
43 | LCDgotoXY(0, baseLine); |
44 | |
45 | for(i=0;i<menuWidth;i++) LCDsendChar(' '); |
46 | |
47 | // LCDgoto(base);
|
48 | LCDgotoXY(0, baseLine); |
49 | |
50 | |
51 | // show entry
|
52 | if(n!=0) |
53 | {
|
54 | |
55 | if(s) LCDsendString(">"); |
56 | else LCDsendString(" "); |
57 | |
58 | LCDgotoXY(1, baseLine); |
59 | LCDsendString(menu->e[n-1].name); |
60 | if(UIsearchMid(menu->e[n-1].id)!=-1) LCDsendChar('z'+4); |
61 | |
62 | // LCDgoto(base+menuWidth-1);
|
63 | LCDgotoXY(menuWidth-1, baseLine); |
64 | if(s) LCDsendString("<"); |
65 | else LCDsendString(" "); |
66 | }
|
67 | |
68 | // show menu
|
69 | else
|
70 | {
|
71 | if(s) LCDsendString(">= "); |
72 | else LCDsendString(" = "); |
73 | |
74 | LCDgotoXY(3, baseLine); |
75 | LCDsendString(menu->menuName); |
76 | |
77 | // LCDgoto(base+menuWidth-3);
|
78 | LCDgotoXY(menuWidth-3, baseLine); |
79 | if(s) LCDsendString(" =<"); |
80 | else LCDsendString(" = "); |
81 | }
|
82 | |
83 | return; |
84 | }
|
85 | |
86 | // select menu item
|
87 | // return number of selected entry
|
88 | // n is preselected entry
|
89 | int UImenuSel(struct UImenu *menu, char n) |
90 | {
|
91 | char chg=1; // anything has changed? |
92 | |
93 | // if 2line, select 1st entry per default
|
94 | // else, select menu as default
|
95 | signed char sel; |
96 | |
97 | // if(UImode==0) sel=n; //+1;
|
98 | // else sel=n;
|
99 | sel=n+1; |
100 | |
101 | while(1) |
102 | {
|
103 | // if anything changed
|
104 | if(chg) |
105 | {
|
106 | // 2line display
|
107 | if(UImode==0) |
108 | {
|
109 | // unselected entry
|
110 | signed char usel=sel-1; |
111 | if(usel<0) usel=menu->entries; |
112 | |
113 | UIshowEntry(menu, 0, usel, 0); |
114 | |
115 | // selected entry
|
116 | UIshowEntry(menu, 1, sel, 1); |
117 | }
|
118 | |
119 | // 1line display
|
120 | if(UImode==1) |
121 | {
|
122 | // show selected entry
|
123 | UIshowEntry(menu, 1, sel, 1); |
124 | |
125 | // show entry number far right
|
126 | LCDgoto(0x40+20-2); |
127 | LCDsendInt(sel); |
128 | }
|
129 | |
130 | chg=0; |
131 | }
|
132 | |
133 | // on key UP
|
134 | if(INPgetReset(KEY_UP)) |
135 | {
|
136 | sel--; |
137 | if(sel<0) sel=menu->entries; |
138 | |
139 | chg=1; |
140 | }
|
141 | |
142 | // on key DOWN
|
143 | if(INPgetReset(KEY_DOWN)) |
144 | {
|
145 | sel++; |
146 | if(sel>menu->entries) sel=0; |
147 | |
148 | chg=1; |
149 | }
|
150 | |
151 | // on key SELECT
|
152 | if(INPgetReset(KEY_OK)) |
153 | {
|
154 | if(sel!=0) return sel-1; |
155 | }
|
156 | |
157 | EventTick(); |
158 | }
|
159 | }
|
160 | |
161 | // search if menu with given mid exists
|
162 | // if so, return number of entry in UImenuList
|
163 | // else, return -1
|
164 | int UIsearchMid(int mid) |
165 | {
|
166 | int n=0; |
167 | |
168 | while(1) |
169 | {
|
170 | if(UImenuList[n]==NULL) return -1; |
171 | if(UImenuList[n]->mid==mid) return n; |
172 | |
173 | n++; |
174 | }
|
175 | |
176 | // dummy
|
177 | return 0; |
178 | }
|
179 | |
180 | // menu exec function
|
181 | int UImenuExec() |
182 | {
|
183 | while(1) |
184 | {
|
185 | // search menu number of mid
|
186 | int n=UIsearchMid(UImid); |
187 | |
188 | // sth failed
|
189 | if(n==-1) return -1; |
190 | |
191 | // show menu and let user select entry
|
192 | int ret; |
193 | |
194 | if(UImidLast==UImid) ret=UImenuSel(UImenuList[n], UIidLast); |
195 | else
|
196 | {
|
197 | UImidLast=-1; |
198 | ret=UImenuSel(UImenuList[n], 0); |
199 | }
|
200 | |
201 | // get id of selected entry
|
202 | int id=UImenuList[n]->e[ret].id; |
203 | |
204 | // if there's a menu with this id as mid, goto submenu
|
205 | if(UIsearchMid(id)!=-1) |
206 | {
|
207 | UImid=id; |
208 | }
|
209 | // else return id
|
210 | else
|
211 | {
|
212 | UImidLast=UImid; |
213 | UIidLast=ret; |
214 | |
215 | return id; |
216 | }
|
217 | |
218 | // event tick
|
219 | EventTick(); |
220 | }
|
221 | |
222 | return 0; |
223 | }
|
Nicht besonders sauber programmiert, aber es funktioniert fehlerfrei (solange die menustruktur in ordnung ist). Das EventTick() kann weg (gehört zu einem einfachen Multimthreading wo Tasks einstellbar alle xyz ms aufgerufen werden, daher in jeder while-schleife), irgendwo in dem Code ist auch noch die Möglichkeit das Menu 1- oder 2-zeilig anzeigen zu lassen (UImode). Die Ausgabe ist in etwa so:
1 | >== Menu Name ==< -- selektierter Eintrag, daher die > < |
2 | Item 1 |
3 | Item 2 |
4 | . |
5 | . |
6 | . |
Verweist die ID von Item xyz auf ein Submenu wird noch "->" angehängt (ist ein Zeichen, das 'z'+4). INPgetReset gehört zum Key-Handler, gibt für die gegebene Key-Mask ungleich 0 zurück falls die Taste gedrückt wurde, und setzt den Status der Taste zurück falls dem so ist.
Ach ja, wär sicher net falsch das mal so umzuändern, dass die Strukturdaten im Flash liegen.
Meinst du weil die Zeilen vorher immer geleert werden? Wie gesagt, als ich den Code geschrieben habe wollte ich eigentlich was ganz anderes machen, brauchte dazu aber ein menu. Außerdem spar ich so die lib-funktion ;) Richtig Sinn macht das Menu übrigens erst mit dem Event-gedödel. Das besteht aus einem Array mit einem Eintrag/Task, da kann man einen Funktionszeiger reinschreiben und das Ausführungsintervall angeben (zB. alle 100msec). Über einen Timer wird dann ermittelt welche Funktionen ausgeführt werden müssen, und das wird dann bei EventTick gemacht. So kann man nebenher zB. ein paar Werte ausgeben, und muss sich dann garnimmer drum kümmern.
I_ H. wrote: > Ach ja, wär sicher net falsch das mal so umzuändern, dass die > Strukturdaten im Flash liegen. Jep, besonders deine strings. Ansonsten: Die Idee sieht sehr sauber aus muss ich sagen.
In den prinzipiellen Aufbau ist auch verhältnismäßig die meiste Zeit geflossen... den Rest kann man ja bei Bedarf auch neu implementieren ;). Frei nach dem Motto Klassen sind dafür da dem ganzen Müll ein sauberes Interface zu verpassen (in dem Fall structs und funktionen). So schaut dann übrigens ein etwas komplexeres Menu aus:
1 | // menu structure
|
2 | struct UImenu menuAkku = |
3 | {
|
4 | "Akku", |
5 | 200, |
6 | 4, |
7 | {
|
8 | {"Info", 210}, |
9 | {"Diag", 230}, |
10 | {"Prog", 220}, |
11 | {"leave", 2000} |
12 | }
|
13 | };
|
14 | |
15 | struct UImenu menuAkkuInfo = |
16 | {
|
17 | "Info", |
18 | 210, |
19 | 5, |
20 | {
|
21 | {"sh. state", 2100}, |
22 | {"sh. energy", 2101}, |
23 | {"sh. all", 2102}, |
24 | {"hide", 2103}, |
25 | {"back", 200} |
26 | }
|
27 | };
|
28 | |
29 | struct UImenu menuAkkuDiag = |
30 | {
|
31 | "Diag", |
32 | 230, |
33 | 4, |
34 | {
|
35 | {"set charge", 2300}, |
36 | {"set disch.", 2301}, |
37 | {"reset en.", 2302}, |
38 | {"back", 200} |
39 | }
|
40 | };
|
41 | |
42 | struct UImenu menuAkkuProg = |
43 | {
|
44 | "Prog", |
45 | 220, |
46 | 6, |
47 | {
|
48 | {"Setup", 240}, |
49 | {"do disch.", 2200}, |
50 | {"do deep d.", 2201}, |
51 | {"do charge", 2202}, |
52 | {"stop", 2203}, |
53 | {"back", 200} |
54 | }
|
55 | };
|
56 | |
57 | struct UImenu menuAkkuProgSet = |
58 | {
|
59 | "Setup", |
60 | 240, |
61 | 8, |
62 | {
|
63 | {"charge", 2400}, |
64 | {"d.charge", 2406}, |
65 | {"cur. cur.", 2401}, |
66 | {"volt thres.", 2402}, |
67 | {"ch. time", 2403}, |
68 | {"d.ch. time", 2404}, |
69 | {"void time", 2405}, |
70 | {"back", 220} |
71 | }
|
72 | };
|
Es gibt noch ein 2. Menu im Zahlenraum 100, den Zeiger auf das Struct mit den Menus (UImenuList) kann man ja umladen. Man könnte jetzt auch noch für jeden Eintrag ein char mit Attributen dazunehmen, mir ist nur bisher noch nix sinnvolles eingefallen.
Sorry, wenn ich den 15 Jahre alten Thread nochmals bemühe, aber offensichtlich hat sich in der zugelassenen C-Syntax etwas geändert: Ich versuche das Beispiel aus diesem ForumsArtikel nachzubauen, aber folgender Code lässt sich einfach nicht (mehr) compilieren:
1 | |
2 | // structure for one single menu entry
|
3 | struct UImenuEntry |
4 | {
|
5 | const char* name; // entry name |
6 | int id; // entry ID |
7 | };
|
8 | |
9 | // structure for a simple menu
|
10 | struct UImenu |
11 | {
|
12 | const char* menuName; // menu name |
13 | int mid; // menu ID will be used to search for this entry |
14 | |
15 | char entries; // how many entries will be in the following list |
16 | struct UImenuEntry e[]; // for list of menu-entries (see struct above) |
17 | };
|
18 | |
19 | /* .......... */
|
20 | |
21 | // definition of main menu
|
22 | struct UImenu menuMain = { |
23 | "Main Menu", // menu name |
24 | 100, // menu id of this menu |
25 | 5, // number of entries in this menu |
26 | {
|
27 | {"Main_01", 1000}, // entry with returncode when selected |
28 | {"Main_02", 1001}, // entry with returncode when selected |
29 | {"Main_03", 1002}, // entry with returncode when selected |
30 | {"Main_04", 1003}, // entry with returncode when selected |
31 | {"submenu", 101}, // entry with ID-Code of the submenu |
32 | }
|
33 | };
|
Fehlermeldung:
1 | [Error] too many initializers for 'UImenuEntry [0]' |
Hab natürlich mal nachgegoogelt und es hängt wahrscheinlich damit zusammen, dass man keine Inline-Initialization für listen-members mit unbekannter Listengröße mehr machen darf. So ganz hab ich es nicht verstanden, aber wenn man auf Stackoverflow nach "too many initializers for 'int [0]' c++" sucht, findet man einen entsprechenden Hinweis... Leider werde ich daraus nicht schlau, wie ich nun die Menüs definieren kann, damit sie der Compiler vernünftig schluckt.... Kann mir ein C-Guru von Euch hier bitte den richtigen Weg weisen... Vielen Dank im Voraus Johann
Hi C geht mir an Allerwertesten vorbei. Aber ich würde ein Menü als verkette (oder doppelt verkette) Liste aufbauen. Das Prinzip gibt es eigentlich in allen Programmiersprachen. Setzt aber die entsprechenden Sprachkenntnisse voraus- MfG Spess
Spess53 .. schrieb: > Hi > > C geht mir an Allerwertesten vorbei. Aber ich würde ein Menü als > verkette (oder doppelt verkette) Liste aufbauen. Das Prinzip gibt es > eigentlich in allen Programmiersprachen. Setzt aber die entsprechenden > Sprachkenntnisse voraus- > > MfG Spess spess53 bezieht sich auf das "linked lists" Konzept: Guck mal hier; da gibt es einen Tutorial: https://www.simplilearn.com/tutorials/data-structure-tutorial/linked-list-in-data-structure#:~:text=A%20linked%20list%20is%20the,reference%20to%20the%20next%20node. https://www.geeksforgeeks.org/data-structures/linked-list/ https://www.geeksforgeeks.org/menu-driven-program-for-all-operations-on-singly-linked-list-in-c/ https://www.geeksforgeeks.org/complete-guide-to-dsa-for-beginners/?ref=shm Würde ich auch so machen.
:
Bearbeitet durch User
Die sicherste Form einer Menüstruktur ist aus meiner Sicht immer eine Finite State Machines oder zu deutsch Automatengraph. Dieser kann vor der Realisierung auf mathematisch Vollständigkeit und Widerspruchsfreiheit geprüft werden. Hier mal ein kleines Beispiel eines einfachen Menüs [1]. [1] https://github.com/Feinmechaniker/micropython/blob/main/projects/FDevT/00%20docs/statemaschine_process.pdf
Beim letzten submenu Entry ist ein Komma Zuviel am Ende, Kopierfehler.
Hallo! Vielen Dank für die Hinweise auf die linked List bzw. State Machine. Keine Sorge, von meinen Programmier-Skills her kann ich sowohl linked lists als auch state machines in Programmen umsetzen. Die Links auf geeksforgeeks.org finde ich trotzdem interessant. Mir hat jedoch der Lösungsansatz in diesem Forums-Artikel gefallen, dass ich lediglich durch Inline-Definition der Menü-Einträge sowohl Menüs, als auch sub-Menüs einhängen kann und die gesamte Menü-Abarbeitung extrem schlank aufgebaut ist. Wenn ich es als linked list löse, müsste ich meiner Meinung nach entweder pro SubMenü eine neue linked list definieren, oder mittels Menue-ID's und Filterung die Submenüs in einer Gesamt-linked-list abarbeiten. Werde noch versuchen, das Inline-Initialisierung-Problem zu lösen und wenn ich das nicht schaffe, werde mal mit einem Lösungsansatz Gesamt-Linked-List beginnen. Vielen Dank!
Es lässt sich aber auch mit dem Komma kompilieren, jedenfalls mit gcc. per cut&paste in https://www.onlinegdb.com/ kopiert, läuft. Anstatt des langen switch/case blocks zur Auswertung würde ich function pointer in die UImenuEntry Strukturen packen.
:
Bearbeitet durch User
Würde das mittels RTOS Thread in einer Klasse mit Thread-member (mind. in einem C Thread, wenn ohne Klassen) abbilden. Diese versendet Messages für Aktionen, und merkt sich den aktuellen Stand (bzw. geht einfach in ein osThreadFlagsWait(), vom Eingabethread aus getriggert). In C++ lassen sich komplexere Menues gut als abgeleitete Klassen eines Basisobjektes erzeugen, von denen jede Klasse weiß, was sie kann. Verwaltung per Polymorphie. Vielleicht ein bischen überzogen, dafür lesbar und einfach erweiterbar. Und das RTOS bewahrt vor polling.
:
Bearbeitet durch User
Johann K. schrieb: > Werde noch versuchen, das Inline-Initialisierung-Problem zu lösen und > wenn ich das nicht schaffe, Prinzipiell geht das wie in Deinem Beispiel, ist aber fehleranfällig weil n manuell bachgepflegt werden muss. Nimm einfach Array und struzktur getrennt: Ein Array unbekannter Größe mit Einträgen, und die Verwaltungsstruktur mit Name, ID, diesem Array und n als countof(dieses Array). Einmal so angelegt, kannst Du x Einträge hinzufügen oder per #define rausnehmen ohne n nachzuführen
J. S. schrieb: > Es lässt sich aber auch mit dem Komma kompilieren, jedenfalls mit gcc. > > per cut&paste in https://www.onlinegdb.com/ kopiert, läuft. > Ja, diese Inline-Initialisierung eines Pointer-Arrays unbestimmter Größe ist bei manchen Compilern noch akzeptiert, aber dürfte nicht exakter Standard sein, weshalb manche Compiler dies nicht akzeptieren... > Anstatt des langen switch/case blocks zur Auswertung würde ich function > pointer in die UImenuEntry Strukturen packen. Ja, es gibt noch einiges Verbesserungspotential wie function-pointer und Strings in den Progmem und non-blocking für den Microprozessor-loop(). Zuerst wollte ich aber einmal den Beispielcode zum laufen bringen und dann entsprechend umbauen... Mit C komme ich ganz gut zu recht inklusive einfachen Pointern. Aber bei Pointer-Listen bzw. Arrays von pointern hab ich noch ein bissl an der Syntax zu knabbern. Was das ist und wie es intern arbeiten soll, verstehe ich, weil ich schon vor 30 Jahren in Assembler auf Großrechnern programmiert habe. Aber in C die richtige Syntax zusammenzubringen ist für mich in manchen Fällen wie diesem eine Herausforderung... Danke für Eure Ratschläge und Unterstützung!
es läuft in C und C++, auch mit den moderneren C++ Varianten. Nur das alte Turbo C/C++ liefert den Fehler (im OnlineGDB ausgeführt). Die Funktionszeiger kann man mit typedef entschärfen, hier auch ohne Anzahl und mit Endekennung:
1 | #include <stdio.h> |
2 | |
3 | // structure for one single menu entry
|
4 | |
5 | typedef void (*UIMenuFn)(); |
6 | |
7 | typedef struct |
8 | {
|
9 | const char* name; // entry name |
10 | UIMenuFn fn; // entry function |
11 | } UImenuEntry; |
12 | |
13 | // structure for a simple menu
|
14 | |
15 | typedef struct |
16 | {
|
17 | const char* menuName; // menu name |
18 | UImenuEntry e[]; // for list of menu-entries (see struct above) |
19 | } UImenu; |
20 | |
21 | /* .......... */
|
22 | |
23 | // definition of main menu
|
24 | |
25 | void menuFn1() { |
26 | printf("function 1\n"); |
27 | }
|
28 | |
29 | void menuFn2() { |
30 | printf("function 2\n"); |
31 | }
|
32 | |
33 | UImenu menuMain = { |
34 | "Main Menu", // menu name |
35 | {
|
36 | {"Main_01", menuFn1}, // entry with returncode when selected |
37 | {"Main_02", menuFn1}, // entry with returncode when selected |
38 | {"Main_03", menuFn2}, // entry with returncode when selected |
39 | {"Main_04", menuFn2}, // entry with returncode when selected |
40 | {"submenu", menuFn2}, // entry with ID-Code of the submenu |
41 | {NULL, 0} |
42 | }
|
43 | };
|
44 | |
45 | |
46 | int main() |
47 | {
|
48 | int i = 0; |
49 | |
50 | printf("menu: %s\n", menuMain.menuName); |
51 | |
52 | while(menuMain.e[i].name) { |
53 | printf(" %s: ", menuMain.e[i].name); |
54 | |
55 | if (menuMain.e[i].fn) { |
56 | menuMain.e[i].fn(); |
57 | }
|
58 | |
59 | i++; |
60 | }
|
61 | |
62 | return 0; |
63 | }
|
:
Bearbeitet durch User
Stefan S. schrieb: > nur über eine if Anweisung Schau dir mal die "Kontrollstrukturen" in C an. Stefan S. schrieb: > weiß jemand von Euch einen besseren Rat? Da es sehr viele Möglichkeiten gibt und nichts von deinem Umfeld bekannt ist, wäre es besser etwas konkreter zu werden. -Wie liegen die Tastinformetionen vor? -Wofür sollen die Tasten im Menü benutzt werden -Wie sieht die Menüstruktur genau aus -Geht es darum Texte zu wechseln oder unterschiedliche Werte zu "stellen" oder zu setzen. -Wie sind die Datenstrukturen der Werte oder Texte die "bedient" werden sollen -Wie ist die Programmstruktur?... Also was genau ist der Umfang und worauf liegt das Hauptaugenmerk usw...
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.