mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Structs in Struct packen, Menü-Aufbau


Autor: Tueftler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen, werte Bastlerfreunde und Profis!

Ich beschäftige mich momentan mit dem Thema MenuStruktur und damit 
einhergehend auch mit Strukturen in C.
Bin noch relativ neu im gesamten Themenkreis, besonders Structs.

Nun stehe ich vor dem Problem, dass ich gerne per Variable auf eine 
Struktur zugreifen will:
Ich habe zwei Strukturen von folgendem Aufbau (in Anlehnung an die 
MC-FAQ)
struct Menueintrag
{
  char   Text[17];
  VoidFnct Function;
};

struct Menueintrag Hauptmenu[] = {
{"++Haupt-Menue++"},    
{"Einstellungen", settings},
{"    Start", begin},
{"   Abbruch", abort},
{"Sel Up Down Info"}
};

struct Menueintrag Einstellungen[]={
  {"+Einstellungen+"},
  {"Set Frequency", setFreq},
  {"  Set Amount", setAmount},
  {" Set Interval", setInterval},
  {"Sel Up Down Info"}
};

Nun möchte ich gerne in einer Funktion namens
void RefreshScreen(struct Menueintrag Menu[])
das Aktuelle Menü auf eineme Display ausgeben. die Ausgabe funktioniert 
auch schon.
Ich kann also momentan über einen Aufruf der Form
RefreshScreen(Hauptmenu);
Das jeweilige Menü darstellen.
Nun ist dies jedoch sehr unpraktisch.
Ich würde gerne diese beiden Menüs (Structs) in ein Array oder in eine 
Struct packen, um dann per Index das jeweilige Menü benennen zu können. 
Also etwa in der Form:
RefreshScreen(Menus(1));
oder
 
RefreshScreen(Menus(aktuellesMenu));
Das hätte den Vorteil, dass ich damit eine Variable definieren kann, die 
das aktuell anzuzeigende Menü repräsentiert.

Könnt Ihr mir da helfen?
Ich habe mir bereits zahlreiche Beiträge zu Structs durchgelesen, bin 
aber noch nicht auf einen grünen Zweig gekommen, Sehe momentan den Wald 
vor Bäumen nicht.
Mit Dank, Tüftler

Autor: Remote One (remote1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tueftler schrieb:
> Nun ist dies jedoch sehr unpraktisch.
> Ich würde gerne diese beiden Menüs (Structs) in ein Array oder in eine
> Struct packen, um dann per Index das jeweilige Menü benennen zu können.


warum packst du das nicht wieder in eine neue struct. Dann kannst du 
bequem mit dem "." referenzieren.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tueftler schrieb:
> Ich beschäftige mich momentan mit dem Thema MenuStruktur und damit
> einhergehend auch mit Strukturen in C.
> Bin noch relativ neu im gesamten Themenkreis, besonders Structs.
>
> Nun stehe ich vor dem Problem, dass ich gerne per Variable auf eine
> Struktur zugreifen will:
> Ich habe zwei Strukturen von folgendem Aufbau (in Anlehnung an die
> MC-FAQ)

Du bist noch ein wenig zu sehr dem Array verpflichtet

Ein Menü ist noch etwas mehr als eine Abfolge von Menüpunkten in einem 
Array :-). Zb hat ein Menü einen Titel (der aber selbst kein 
auswählbarer Menüpunkt ist) und es hat eine Anzahl von Menüpunkten (wie 
stellen denn deine verarbeitenden Funktionen fest, wieviele Menüpuntke 
es gibt?)

(Ausserdem solltest du dir angewöhnen, für Texte, die sich nicht ändern, 
keine char-Arrays zu allokieren, sondern ganz einfach nur einen Pointer 
auf const char einzubauen. Zum einen spart das Speicher, zum anderen 
wirst du es dir danken wenn du anfängst die Texte ins Flash auszulagern)

struct Menueintrag
{
  const char* Text;
  VoidFnct    Function;
};

struct Menu
{
  const char*         Title;
  uint8_t             NrEntries;
  struct Menueeintrag Entries[];
};

struct Menu HauptMenu =
{  "++Haupt-Menue++",
   3,
   { { "Einstellungen", settings },
     { "Start",         begin },
     { "Abbruch",       abort},
   }
};

struct Menu SettingsMenu =
{  "+Einstellungen+",
   3,
   { { "Set Frequency", setFreq },
     { "Set Amount",    setAmount },
     { "Set Interval",  setInterval },
   }
};

> Nun möchte ich gerne in einer Funktion namens
>
> void RefreshScreen(struct Menueintrag Menu[])
> 
> das Aktuelle Menü auf eineme Display ausgeben. die Ausgabe funktioniert
> auch schon.
> Ich kann also momentan über einen Aufruf der Form
>
> RefreshScreen(Hauptmenu);
> 
> Das jeweilige Menü darstellen.
> Nun ist dies jedoch sehr unpraktisch.

Ist es.

> Ich würde gerne diese beiden Menüs (Structs) in ein Array oder in eine
> Struct packen, um dann per Index das jeweilige Menü benennen zu können.

Brauchst du im Grunde nicht.
Es reicht, wenn du eine Pointer Variable hast, die auf das aktuelle Menü 
zeigt

struct Menu* actMenu;


> Also etwa in der Form:
>
> RefreshScreen(Menus(1));
> 
> oder
>
> RefreshScreen(Menus(aktuellesMenu));
> 

oder einfach

  actMenu = &HauptMenu;

  RefreshScreen( actMenu );

Autor: Tueftler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl,
Vielen Dank für deine ausführliche Antwort, diese hat mich bereits sehr 
viel weiter gebracht. Ich habe das jetzt mal so wie von dir 
vorgeschlagen implementiert. Nun habe ich allerdings wiederum ein 
Problem.
Ich versuche mal zu erklären was ich überhaupt gemacht hab, um zu 
prüfen, dass ich das auch verstanden habe:
Als erstes definiere ich eine Struktur mit Namen Menueeintrag, deren 
Einträge jeweils aus einem Text und einer Funktion bestehen.
struct Menueeintrag
{
  const char*   Text;
  VoidFnct Function;
};

Nun definiere ich eine neue Structure, die sich zusammensetzt aus:
-einem Pointer auf ein Char-?Eintrag? mit Namen Title
-einer Variable vom typ uint8_t mit Namen NrEntries
-sowie einer Structur vom obigen "Typ" Menueeintrag mit Namen Entries
struct Menue{      
  const char*    Title;
  uint8_t    NrEntries;
  struct Menueeintrag   Entries[];      //
};

Nun erzeuge ich eine Struktur vom Typ Menue und trage die Werte ein.
struct Menue Einstellungen =
{"++Einstellungen++",
  3,
{
  {"   Messintervall", setInterval},
  {"     Frequenz", setFreq},
  {"     Spielzahl", setAmount}
}
};

Nun definiere ich noch einen Pointer der auf den Typ Menue zeigt und 
actMenue heisst:
struct Menue* actMenue;    

Die nun folgende Funktion bekommt den oben definierten Pointer als 
Argument übergeben und soll den Menutitel sowie die Texte der einzelnen 
Einträge ausgeben: Hier fängt das Problem an:
Ich muss zuerst den Inhalt des übergebenen Pointers in eine lokale 
Struktur laden, wiederum vom Typ Menue.
Anschliessend kann ich auf den Title der lokalen Struktur zugreifen und 
diesen ausgeben. Auch kann ich auf NrEntries zugreifen und diese korrekt 
auslesen. Sobald ich allerdings auf die Texte der intregrierten Struct 
Menueeintrag zugreifen will, kommen nur noch wirre Zeichen. (in der 
Schleife)
void RefreshScreen(struct Menue *Menuelokal)
{
  struct Menue Menuelocal =*Menuelokal;
   
  WriteString(2,0,Menuelocal.Title);  

  for (uint8_t z=1; z<=Menuelocal.NrEntries; z++)
  {
  WriteString(2,z+2,Menuelocal.Entries[z-1].Text);
  }
}

Ander hingegen wenn ich nicht den Pointerinhalt ausgebe sondern direkt 
den Inhalt eines Menus:
WriteString(2,5,HauptMenue.Entries[1].Text);
Diese Ausgabe funktioniert fehlerfrei.

Meine Frage also:
1. Wie greife ich auf die Elemente der Struct in der Struct zu? :)
2. Welches Buch erklärt diese Sachen ausführlich und verständlich, evtl. 
mit Beispielen?

Vielen Dank für deine Mühen und natürlich auch allen Anderen die mir 
weiterhelfen können oder es versuchen.

Autor: abcxyz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In RefreshScreen brauchst du keine lokale Struktur anzulegen.
Nutze einfach den Pointer um auf die Elemente zuzugreifen:

void RefreshScreen(struct Menue *actMenue)
{


  WriteString(2,0,actMenue->Title);

...

      WriteString(2,z+2,actMenue->Entries[z-1].Text);
....

Autor: Tueftler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal,

Das geht nun sehr gut, Vielen Dank für diese Hilfe.

Habe nun das Problem, dass ich einer neuen Funktion zwei Argumente 
(Pointer) übergebe.

void ExecCommand(struct Menue *actMenue, uint8_t *Selection)
{
actMenue->Entries[*Selection].Function();
}

Allerdings klappt dies nicht, Ich lade extern in den Pointerbereich eine 
Zahl:
(*Selection)=1;
Dann rufe ich die Funktion auf und übergebe ihr die Adresse an der die 
Zahl steht, die ich vorher hineingeschrieben habe.
ExecCommand(actMenue,&Selection);

Nun wird jedoch immer das gleiche Unterprogramm aufgerufen, egal welche 
Zahl ich vorher in die Speicheradresse auf die der Pointer zeigt 
geschrieben habe.

Also
(*Selection)=1;
ExecCommand(actMenue,&Selection);
(*Selection)=2;
ExecCommand(actMenue,&Selection);
(*Selection)=3;
ExecCommand(actMenue,&Selection);
Ruft immer das gleiche Untermenü auf.

Was mache ich da noch falsch?
Danke für eure Bemühungen.

Autor: ozo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meiner Ansicht nach hast du da einen "Pointer" zuviel drin.
Statt
(*Selection)=2;
ExecCommand(actMenue,&Selection);
sollte es gefühlt eher so aussehen:
u8_t Selection;
Selection=2;
ExecCommand(actMenue,&Selection);
Aber eigentlich kannst du doch auf die Übergabe von Selection als 
Pointer verzichten und direkt Selection übergeben? Oder soll deine 
Funktion schreibend auf Selection zugreifen können?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.