Newsgroup: it.comp.lang.c++
Titolo: Tutorial per menu (embedded)

Salve, sapete consigliarmi un tutorial per scrivere un menu dinamico in C++ 
?

 ?
In italiano o in inglese? E poi, hai menzionato embedded per dire che 
lavori su un sistema embedded oppure perchï¿œ vuoi creare il menu 
completamente in C++ senza usare librerie esterne? In particolare, hai 
la possibilitï¿œ di utilizzare la STL?
Avere qualche informazione in piï¿œ riguardo al tuo ambito di 
programmazione sarebbe d'aiuto - magari ti ritrovi a non dover creare il 
tutto di sana pianta ma solo a riutilizzare funzionalitï¿œ esistenti.
-- 
FSC
http://userscripts.org/scripts/show/59948

 FSChttp://
userscripts.org/scripts/show/59948
new member of ur group



???
-- 
FSC
http://userscripts.org/scripts/show/59948

 possibilità di utilizzare la STL?
Ciao, lavoro su una scheda elettronica con micro + display +tastiera.
Non mi risulta siano disponibili librerie.
Il sistema può essere programmato in C o C++,
vorrei imbastire un menu con una classe c++  studiata bene in modo da poter 
assolvere alle piu frequenti richieste, per esempio:
- funzione "torna al menu precedente"
- come gestire la pressione del tasto al menu corrente
Immagino che ci siano gia passati in tanti, e vorrei prendere spunto prima 
di iniziare a scrivere codice!



Quindi si tratta di un terminale a caratteri (monoriga o qualcosa del 
genere?) oppure c'è una qualche interfaccia grafica? (ne dubito)
Ovviamente, se devi interagire in IO con tastiera e display come minimo 
avrai a disposizione <iostream>, oppure devi utilizzare funzioni 
specifiche tramite il comando system?
Chiedo questo perché la disponibilità o meno della STL (std::string e 
std::vector in particolare) sono importanti per non dannarti l'anima... 
io onestamente sono un hobbista, quindi non ti posso dare indicazioni 
"professionali" al riguardo anche se me la cavicchio...
...la cosa non è pertinente al 100%, ma per farti capire, dalla pagina 
http://fscode.altervista.org
 puoi scaricare un programma C++ che ho 
costruito da cima a fondo usando solo la libreria SDL (Simple 
DirectMedia Layer) per le primitive grafiche di disegno a schermo, 
quindi ho dovuto combattere con roba tipo la gerarchia dei vari frames / 
bottoni / etichette che mi sono creato e gestire il passaggio dei click 
ai vari widget - in questo programma l'interazione con la tastiera è una 
cosa di questo tipo (riscrivo a mente qui nel newsreader quindi non mi 
bastonate se faccio degli errori stupidi):
struct Command {
   char shortcut;
   void (*callback)();
// altra roba tipo "std::string caption;"
// versione semplificata del costruttore, giusto per intenderci...
   Command(char ch, void (*cb)()) : shortcut(ch), callback(cb) {}
};
struct che inserisco in un vector in questo modo:
std::vector<Command> commands;
commands.push_back(Command('d', display));
dove display è dichiarato come:
void display() {
   //...
}
poi c'è un loop che legge dalla tastiera e passa i comandi ad un altro 
loop che chiama le callback in base al carattere selezionato:
for(int i = 0; i < commands.size(); ++i) {
   if(ch == commands[i].shortcut) {
     commands[i].callback();
     break;
   }
}
Il codice che ho arrangiato qui al volo è molto più semplice di quello 
che uso nel programma, ma il concetto è questo e non è complicato 
estenderlo e migliorarlo per applicarlo ad una gerarchia di menu.
Spero che questi due centesimi ti siano d'aiuto in qualche modo...
-- 
FSC
http://userscripts.org/scripts/show/59948



Esempio arrabattato per distrazione:
//-------
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct MenuItem {
     char shortcut;
     bool (*callback)();
     MenuItem* parent;
     vector<MenuItem*> children;
     string caption;
     MenuItem(string caption, char shortcut,
              MenuItem* parent = 0, bool (*callback)() = 0)
             : caption(caption), shortcut(shortcut),
               parent(parent), callback(callback) {
         if (parent) {
             parent->children.push_back(this);
         }
     }
     void display() {
         if (children.size()) {
             cout << "-------" << endl;
             cout << shortcut << " - " << caption << "..." << endl;
             for (int i = 0; i < children.size(); ++i) {
                 if (children[i]) {
                     cout << "+ " << children[i]->shortcut
                     << " - " << children[i]-> caption;
                     if(children[i]->callback) {
                         cout << "!" << endl;
                     } else {
                         cout << "..." << endl;
                     }
                 }
             }
             cout << "-------" << endl;
         } else if (parent) {
             parent->display();
         }
     }
     MenuItem* execute() {
         if (callback) {
             if(!callback()) {
                 return 0;
             }
             if(parent) return parent;
         } else {
             display();
             string command;
             for (;;) {
                 getline(cin, command);
                 if (command.size()) {
                     char ch = 
command.at
(0);
                     if (ch == shortcut) {
                         if (parent) return parent;
                         display();
                     } else {
                         for (int i = 0; i < children.size(); ++i) {
                             if (ch == 
children.at
(i)->shortcut) {
                                 return 
children.at
(i);
                             }
                         }
                         cout << ">>> Unknown command" << endl;
                         return this;
                     }
                 } else {
                     return this;
                 }
             }
         }
         return this;
     }
     void interact() {
         MenuItem* current = this;
         while(current = current->execute());
     }
};
bool saveIt() {
     cout << ">>> Saved" << endl;
     return true;
}
bool loadIt() {
     cout << ">>> Loaded" << endl;
     return true;
}
bool eraseIt() {
     cout << ">>> Erased" << endl;
     return true;
}
bool cutIt() {
     cout << ">>> Cut" << endl;
     return true;
}
bool copyIt() {
     cout << ">>> Copied" << endl;
     return true;
}
bool pasteIt() {
     cout << ">>> Pasted" << endl;
     return true;
}
bool parseIt() {
     cout << ">>> Parsed" << endl;
     return true;
}
bool finish_iteration() {
     return false;
}
int main() {
     MenuItem menu("Menu", ' ');
     MenuItem file("File", 'f', &menu);
     MenuItem edit("Edit", 'e', &menu);
     MenuItem advanced("Advanced", 'a', &edit);
     new MenuItem("Exit", 'x', &menu, finish_iteration);
     new MenuItem("Save", 's', &file, saveIt);
     new MenuItem("Load", 'l', &file, loadIt);
     new MenuItem("Erase", 'e', &file, eraseIt);
     new MenuItem("Cut", 'x', &edit, cutIt);
     new MenuItem("Copy", 'c', &edit, copyIt);
     new MenuItem("Paste", 'p', &edit, pasteIt);
     new MenuItem("Parse", 'p', &advanced, parseIt);
     menu.interact();
     return 0;
}
//-------
Questo è solo il più terra-terra degli approcci, condensato in una sola 
classe e senza possibilità di passare callback differenziate per argomento.
Il meccanismo di interazione è decisamente basilare:
- accetta come input qualsiasi stringa che inizi con una shortcut conosciuta
- l'uscita dal loop principale interact() si basa sul valore di ritorno 
delle callback
- la navigazione a ritroso sul menu si effettua digitando la shortcut 
del menu corrente
- le shortcut hanno visibilità limitata alle voci visualizzate
- essendo una struct senza membri privati (come anche basandosi sul 
concetto non imposto "o hai children o hai callback, altrimenti non 
servi") così com'è si presta a svariati malfunzionamenti.
Se hai qualsiasi domanda chiedi pure.
-- 
FSC
http://userscripts.org/scripts/show/59948

 servi") così com'è si presta a svariati malfunzionamenti.
Interessante lezione! ;)



Uhm... è ben lungi dal mio concetto ideale di "lezione" (non potrei 
onestamente permettermelo, non senza incappare in gravi lacune 
soprattutto in ambito professionale)... se vogliamo, possiamo prenderlo 
come un esempio (positivo e negativo) di come abbozzare qualcosa di 
funzionante ma decisamente migliorabile.
Spero che sia di qualche aiuto all'OP - non so ancora se ha la 
possibilità di usare la STL, e la cosa fa una _enorme_ differenza.
Se non eri sarcastico, comunque, ti ringrazio per il complimento :-)
-- 
FSC
http://userscripts.org/scripts/show/59948

 Se non eri sarcastico, comunque, ti ringrazio per il complimento :-)
complimento più che sincero, sul serio! ;)
saluti



Ah OK, scusa la paranoia :-)
-- 
FSC
http://userscripts.org/scripts/show/59948

> Se hai qualsiasi domanda chiedi pure.
Spero di riuscire a capire bene tutto, eventualmente ti disturbo ancora,
Voglio ringraziarti e complimentarmi a mia volta.
Federico



Ti ringrazio, però adesso non esageriamo eh, siamo ancora su Usenet sì? ;-)
Nessun disturbo, chiedi pure senza remore, ho avuto la fortuna di essere 
aiutato dalla comunità e mi sembra il minimo ricambiare fin dove posso.
Nel caso, ricordati di indicare eventuali altre limitazioni o 
disponibilità aggiuntive del tuo ambito - se sappiamo quali frecce 
abbiamo a disposizione le soluzioni possono essere più mirate ed 
efficaci. Sembra che non ci siano problemi per la STL, e questo è già un 
gran passo :-)
-- 
  FSC - 
http://userscripts.org/scripts/show/59948
 
http://fscode.altervista.org
 - 
http://sardinias.com

> Voglio ringraziarti e complimentarmi a mia volta.
Ciao, ho provato a comprendere il codice che mi hai suggerito, e come vedi
dal tempo che è trascorso .. di spunti ce ne hai messi parecchi! Per prima
cosa mi sono informato sul container <vector> che non conoscevo (programmo
per ambienti embedded in C) e se da una parte ho scoperto una cosa  molto
interessante, dall'altra ho scoperto che il mio ambiente di sviluppo non
supporta la Stdlib, ma ne supporta un sottoinsieme (embedded c++ compliant)
che purtroppo non comprende <vector>
A questo punto sto tentando di riscrivere il menu di esempio senza usare 
<vector>.
Appena riesco a produrre qualcosa di buono lo posto!

 Appena riesco a produrre qualcosa di buono lo posto!
Take your time, ma nel frattempo mi piacerebbe sapere con maggiore 
precisione gli strumenti che stai utilizzando. Più dettagli mi fai 
sapere, maggiori sono le probabilità che riesco a tirarti fuori una 
soluzione comparabile a partire dal subset che hai a disposizione.


, on 23/08/2010 18:25:26, wrote:

Quando hai un minuto di tempo prova un po' questo template - sostituisci 
vector con Vector nel menu di esempio.
Non sono sicuro che sia privo di bug ed è decisamente incompleto, ma è 
più che sufficiente a supportare il menu di cui sopra (che lascia 
altrettanto a desiderare).
Spero non salti fuori che non hai <new> e che in più non riesci a 
compilare il template qua sotto (le istruzioni cruciali sono i placement 
new nelle funzioni "create()")... ma ne dubito. Dovrebbe funzionare.
Resto in attesa di maggiori dettagli (tipo l'elenco completo degli 
header standard che hai a disposizione), giusto per curiosità.
Enjoy, for what is worth:
//-------
#include <new>
template<class T> class Vector {
public:
     typedef T                   value_type;
     typedef value_type&         reference;
     typedef const value_type&   const_reference;
     typedef value_type*         iterator;
     typedef const value_type*   const_iterator;
     typedef size_t              size_type;
     Vector(size_t n = 0) : start(0), finish(0), end_of_storage(0) {
         if (n) {
             reserve(n);
             value_type v;
             for (size_type i = 0; i < n; ++i) {
                 create(start + i, v);
             }
             finish = start + n;
         }
     }
     size_type size() const {
         return finish - start;
     }
     size_type capacity() const {
         return end_of_storage - start;
     }
     reference operator[](size_type index) {
         return start[index];
     }
     const_reference operator[](size_type index) const {
         return start[index];
     }
     reference at(size_type index) {
         return start[index];
     }
     const_reference at(size_type index) const {
         return start[index];
     }
     bool empty() const {
         return size() == 0;
     }
     reference front() {
         return *start;
     }
     const_reference front() const {
         return *start;
     }
     reference back() {
         return *(finish-1);
     }
     const_reference back() const {
         return *(finish-1);
     }
     iterator begin() {
         return start;
     }
     const_iterator begin() const {
         return start;
     }
     iterator end() {
         return finish;
     }
     const_iterator end() const {
         return finish;
     }
     void clear() {
         if (start) {
             destroy(start, finish);
             finish = start;
         }
     }
     void reserve(size_type n) {
         if (capacity() == 0) {
             start = allocate(n);
             finish = start;
             end_of_storage = start + n;
         } else if (n > capacity()) {
             value_type* old_start = start;
             start = allocate(n);
             value_type* from = old_start;
             value_type* to = start;
             while (from < finish) {
                 create(to, *from);
                 ++to;
                 ++from;
             }
             destroy(old_start, finish);
             finish =  start + (finish - old_start);
             end_of_storage = start + n;
             deallocate(old_start);
         }
     }
     void push_back(const value_type& t) {
         if (finish == end_of_storage) {
             if (capacity()) {
                 reserve(capacity() * 2);
             } else {
                 reserve(1);
             }
         }
         create(finish, t);
         ++finish;
     }
     void pop_back() {
         --finish;
         destroy(finish);
     }
     ~Vector() {
         if (start) {
             destroy(start, finish);
             deallocate(start);
         }
     }
private:
     value_type* start;
     value_type* finish;
     value_type* end_of_storage;
     static value_type* allocate(size_t n) {
         return
             reinterpret_cast<value_type*> (
                 new char[sizeof(value_type) * n]
             );
     }
     static void deallocate(void* ptr) {
         operator delete[] (ptr);
     }
     static value_type* create(void* ptr) {
         return new(ptr) value_type();
     }
     static value_type* create(void* ptr, const value_type& t) {
         return new(ptr) value_type(t);
     }
     static void destroy(value_type* ptr) {
         ptr->~value_type();
     }
     static void destroy(value_type* begin_ptr, value_type* end_ptr) {
         while (--end_ptr >= begin_ptr) {
             destroy(end_ptr);
         }
     }
};
//-------




<codice eliso>
In attesa di altre informazioni sto continuando a studiare la gestione 
dinamica della memoria non inizializzata, con l'aiuto dei frequentatori 
di c.l.c++, e ovviamente sto continuando ad implementare il template Vector.
Mi è stato segnalato STLport:
http://www.stlport.org/
Non so se puoi installare qualcosa del genere nel dispositivo per il 
quale stai sviluppando e in verità non so nemmeno quanto eventualmente 
potrebbe tornarti utile (suppongo parecchio, dato che così avresti 
veramente tutta la Libreria Standard a disposizione).
Beh, io te l'ho segnalato, il mio dovere l'ho fatto ;-)
