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.
Funtionspointer wären auch eine Alternative.
...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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
Im Einsatz sieht das dann so aus:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
129 | |
130 | |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | |
170 | |
171 | |
172 | |
173 | |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | |
190 | |
191 | |
192 | |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | |
205 | |
206 | |
207 | |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | |
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 | |
2 | |
3 | |
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.
Kannst dir dazu auch mal diesen Thread angucken: Beitrag "strlen bei mehrdimensionalen Strings"
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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
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 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
Fehlermeldung:
1 |
|
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
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.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.
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].
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.
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.
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
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 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
nur über eine if Anweisung
Schau dir mal die "Kontrollstrukturen" in C an.
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...
Ich sage nur Strategy Pattern dazu.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.