5
Ho creato molte sezioni diverse del sistema GUI per Nintendo DS come pulsanti e caselle di testo e caselle di controllo, ma ho bisogno di un modo per nascondere queste classi in una classe Gui in modo da poter disegnare tutto sullo schermo tutto in una volta e selezionare subito tutti i pulsanti per verificare se sono stati premuti dei pulsanti. La mia domanda è: qual è il modo migliore per organizzare tutte le classi (come pulsanti e caselle di testo) in una classe GUI?
Ecco un modo in cui pensavo, ma non mi sembra corretto:
Modificare: Sto usando C++.
Class Gui (public: void update_all (); void draw_all () const; int add_button (Button * button); // Restituisce l'id del pulsante void remove_button (int button_id); private: Button * buttons; int num_buttons;)
Questo codice ha diversi problemi, ma volevo solo darti un'idea di quello che voglio.
5 risposte
Ordinamento:
Attività
2
Questa domanda è molto simile a quella che stavo per postare, solo la mia è per la programmazione Sony PSP.
Sto cercando qualcosa da un po', ho consultato alcuni libri e VTM e finora questa è un'idea approssimativa di semplici sistemi di interfaccia utente.
Class uiElement () (... virtual void Update () = 0; virtual void Draw () = 0; ...) class uiButton () public: uiElement (... virtual void Update (); virtual void Draw () ; ...) class uiTextbox () public: uiElement (... virtual void Update (); virtual void Draw (); ...) ... // Other ui Elements class uiWindow () (... void Update (); void Draw (); void AddElement (uiElement * Element); void RemoveElement (uiElement * Element); std :: list
Il principio è creare una finestra e collegarvi gli elementi dell'interfaccia utente e chiamare i metodi render e update dalle corrispondenti funzioni principali.
Non funziona ancora per me, poiché ho problemi con il codice del disegno. Con varie API su PC e PSP, sto esaminando il codice wrapper per OpenGL e psp gu.
Spero questo sia di aiuto.
0
Una strategia utile da tenere a mente potrebbe essere il modello composito. A un livello basso, può consentire di gestire più facilmente tutti gli oggetti della GUI (e le raccolte di oggetti) dopo che sono stati creati. Ma non so cosa abbia a che fare con il design della GUI, quindi un posto dove trovare ispirazione generale è nel codice sorgente di un progetto esistente. WxWidgets è una GUI multipiattaforma con codice sorgente disponibile. Buona fortuna con il vostro progetto!
0
3
Per chi fosse interessato, ecco il mio toolkit GUI open source con licenza BSD per DS:
La risposta di Subject2k è abbastanza buona, ma consiglierei seriamente di avere il codice che contiene gli elementi dell'interfaccia figlio in una classe uiElement di base. Questo è lo schema che ho seguito su Whoopsi.
Se tu non supportalo in una classe base, incontrerai seri problemi quando cercherai di implementare qualcosa di più complesso di una casella di testo e un pulsante. Ad esempio:
- I riquadri tabulari possono essere modellati come più pulsanti raggruppati in un singolo elemento dell'interfaccia utente padre che fornisce l'esclusività reciproca;
- Gruppi di stazioni radio (nel tempo);
- Le barre di scorrimento possono essere rappresentate come elementi slider/gutter e pulsanti su/giù;
- Gli elenchi di scorrimento possono essere presentati come un contenitore e più elementi dell'interfaccia utente.
Inoltre, vale la pena ricordare che DS ha un processore a 66 MHz e 4 MB di RAM, che viene utilizzato sia per memorizzare il programma che per eseguirlo (i dischi DS vengono caricati nella RAM prima di essere eseguiti). Dovresti davvero pensarlo come un sistema embedded, il che significa che non c'è STL. Ho rimosso STL da Woopsi e sono riuscito a mantenere 0,5 MB. Non molto per gli standard desktop, ma è 1/8 della memoria DS totale disponibile consumata dalla spazzatura STL.
Ho dettagliato l'intero processo di scrittura di un'interfaccia utente sul mio blog:
Include una descrizione di due algoritmi che ho ideato per ridisegnare lo schermo, che è la parte difficile della creazione di una GUI (uno rompe semplicemente i rettangoli e ricorda le aree visibili, e l'altro usa alberi BSP, che è molto più efficiente e più facile da capire), suggerimenti per l'ottimizzazione, ecc. .d.
Annotazione: Sono studiati gli elementi visivi che compongono l'interfaccia grafica utente, il loro layout, la politica di dimensionamento, le connessioni segnale-slot, gli elementi dell'interfaccia grafica e il loro utilizzo.
13.1 Widget
I widget sono gli elementi visivi che compongono l'interfaccia utente grafica.
Esempi di widget:
- Pulsante (classe QPushButton);
- Etichetta (classe QLabel);
- Campo di input (classe QLineEdit);
- Campo contatore numerico (classe QSpinBox);
- Barra di scorrimento (classe QScrollBar).
Qt ha circa 50 classi già pronte di elementi grafici disponibili per l'uso. La classe genitore per tutti i widget è la classe QWidget. Da esso vengono ereditate tutte le principali proprietà degli elementi visivi, che considereremo attentamente. Iniziamo la nostra esplorazione dei modi per sviluppare programmi con un'interfaccia grafica con un esempio.
Creiamo un file di progetto vuoto. Avvia la procedura guidata del progetto e seleziona l'elemento nella sezione Progetti Altro progetto... Quindi, seleziona il tipo di progetto Progetto Qt vuoto... Aggiungi contenuto al file di progetto:
TEMPLATE = app # moduli Qt che useremo QT + = widget # Aggiungi un modulo widget per lavorare con i widget (richiesto per Qt5). TARGET = widget # Nome file eseguibile SOURCES + = \ main.cpp
Ora creiamo un semplice programma con una finestra in cui visualizzeremo l'iscrizione. Impostiamo la dimensione della finestra e il testo del suo titolo, oltre a impostare il carattere per la didascalia. Per fare ciò, crea un file main.cpp con il seguente contenuto:
#includere
Come puoi vedere, gli elementi che compongono le interfacce in Qt hanno una loro posizione e dimensione - la cosiddetta "geometria" - e occupano quindi la corrispondente area rettangolare sullo schermo (vedi Figura 13.1). Inoltre, ciascuno degli elementi ha impostazioni che ne determinano il comportamento e l'aspetto.
Riso. 13.1.
Per creare una struttura, i widget sono organizzati in una gerarchia su base parziale. Ciascuno dei widget può contenere altri widget. Tale elemento visivo diventa il "genitore" (widget genitore) degli elementi che contiene. Si noti che tale relazione non deve essere confusa con l'ereditarietà in C++, la relazione tra le classi in un programma. Le relazioni tra i widget sono relazioni tra gli oggetti. Questa relazione ha diverse conseguenze:
- l'elemento genitore sarà responsabile dell'eliminazione dell'elemento figlio: se il widget genitore viene eliminato, eliminerà automaticamente tutti gli elementi figlio;
- il widget genitore posiziona i widget figli al suo interno, le parti dei widget figli che vanno oltre il genitore saranno invisibili;
- parte dello stato del widget genitore viene passato al figlio - questo riguarda alcune proprietà (visibilità, attività) e stili che vengono imposti all'elemento visivo.
I widget che non hanno un genitore (widget di livello superiore) sembrano finestre separate nel programma. Diamo un'occhiata a un esempio. Chiamiamo il nuovo progetto ParentExample. Il file di progetto conterrà le solite impostazioni per un progetto GUI:
TEMPLATE = app TARGET = ParentExample QT + = widget
Per il widget che utilizzeremo come finestra principale, creeremo una nuova classe. Per questo nella categoria File e classi selezionare la sezione C++ e selezionare la Classe C++ (vedi Figura 13.2).
Il prossimo passo è creare diversi elementi sulla finestra. Per fare ciò, apri il file parentwidget.cpp e modifica il codice del costruttore della classe. Per visualizzare gli elementi, devi solo crearli nel costruttore della classe e impostare ParentWidget come padre per loro. Il codice parentwidget.cpp ha questo aspetto:
#include "parentwidget.h" #include
Poiché il genitore è ParentWidget, l'etichetta (QLabel), il pulsante (QPushButton) e la casella di testo (QLineEdit) sono al suo interno. La posizione dei widget figlio è relativa all'angolo superiore sinistro del padre. Questo è facile da verificare modificando la dimensione e la posizione della finestra del nostro programma. Notare come abbiamo creato gli elementi dell'interfaccia utente nell'heap utilizzando l'operatore new. Ciò garantisce che nessun elemento venga rimosso al termine del costruttore ParentWidget.
Prenoto subito che C ++ è la mia lingua preferita, ci scrivo praticamente "fin dall'infanzia" e non negherò la sua importanza come la migliore delle migliori lingue per scrivere programmi per qualsiasi scopo . Inoltre, non vedo alcun motivo per iniziare un altro holivar o misurarsi con "indicatori". Questo articolo è solo una descrizione di una brutta esperienza con il linguaggio, spiegandone alcuni aspetti, la cui conoscenza aiuterà altri programmatori in futuro.
Un giorno mi sono imbattuto in una libreria di classi GUI in via di sviluppo. Dal punto di vista del C++, più precisamente delle sue classi, istanze e gerarchie, questo linguaggio sembra incredibilmente vicino al concetto di controllo GUI, in particolare elementi come widget, finestre di classe e sottofinestre. I modelli OO di C++ e il sistema a finestre sono comunque diversi. C++ è stato concepito come un linguaggio "statico" con ambito token, controllo del tipo statico e gerarchie definite in fase di compilazione. Le finestre ei loro oggetti, invece, sono di natura dinamica, di solito vivono al di fuori della particolare procedura o blocco con cui sono state create; le gerarchie dei widget sono in gran parte determinate da layout, visibilità e flussi di eventi. Le basi dell'interfaccia utente grafica come la finestra dinamica e geometrica e le gerarchie di controllo, il flusso di eventi non sono direttamente supportate dalla sintassi o dalla semantica C ++. Pertanto, queste funzionalità dovrebbero essere riprodotte nel codice della GUI C ++. Questo porta alla duplicazione di toolkit grafici, o funzionalità del window manager, il codice si "gonfia", siamo costretti ad abbandonare molte delle caratteristiche "forti" del C++ (ad esempio, il controllo del tipo in fase di compilazione). Questo articolo fornisce alcuni semplici esempi di C++/GUI "no docking".
Non creare costruttori (o almeno non usarli)
Quando la classe risultante sovrascrive il metodo virtuale della classe genitore, tenere presente che la sovrascrittura non ha effetto mentre il costruttore della classe base è in esecuzione. Ciò è particolarmente fastidioso quando gli oggetti richiedono widget che rispondono agli eventi della GUI. Supponiamo che la classe Finestra_di base aveva lo scopo di creare una finestra in bianco e nero vaniglia sullo schermo:
Classe Basic_Window (
pubblico:
Basic_Window (Rect rect) (gt_create_window (rect, visibile, questo);)
vuoto virtuale handle_create_event () (set_background (WHITE);)
};
Qui gt_create_window ()è responsabile della chiamata a basso livello del toolkit grafico principale (ad esempio, xvt_win_create ()). Questa funzione alloca lo spazio per i dati della strumentazione, notifica al window manager, registra questo oggetto come un ricevitore di eventi e, nell'esempio sopra, inizializza l'output grafico alla finestra sullo schermo.
Diciamo che vogliamo istanziare Finestra_di base ma con sfondo rosso. Di solito, per modificare il comportamento di una classe, è necessario estrarne e sovrascrivere i metodi virtuali corrispondenti. stiamo scrivendo:
Classe RedWindow: public Basic_Window (
vuoto virtuale handle_create_event () (set_background (RED);)
pubblico:
RedWindow (Rect rect): Basic_Window (Rect rect) ()
};
RedWindow red_window (default_rect);
Ma finestra_rossa apparirà bianco, non rosso! Creare RedWindow, il genitore deve essere creato prima. Dopo aver finito Basic_Window :: Basic_Window (), tavoli virtuali RedWindow avere effetto, metodo handle_create_event() diventa inutilizzabile e il costruttore Finestra Rossa () eseguita. Costruttore Finestra_base () registra un oggetto di strumenti grafici che inizia immediatamente a inviare eventi all'oggetto (ad esempio, un evento CREATE). Costruttore Finestra_base () non ancora terminato (non garantito), quindi il metodo virtuale sovrascritto non è ancora attivo. Pertanto, l'evento CREATE verrà gestito Basic_Window :: handle_create_event ()... Tavoli virtuali RedWindow le classi verranno create solo quando la classe base è completamente compilata, cioè quando la finestra è già sullo schermo. La modifica del colore della finestra in questa fase porterà a un fastidioso errore.
C'è una soluzione semplice: impedire a ogni costruttore di registrare un oggetto toolbox grafico. La gestione degli eventi sarà strutturata per evitare che l'inizializzazione finisca con le classi derivate. Si è tentati di pensare ai widget sullo schermo come al "volto" dell'oggetto GUI di un'applicazione in memoria. Come mostra l'esempio sopra, questa relazione tra uno schermo e un oggetto C++ non è facile da implementare: nascono separatamente.
Nessun mezzo sintattico per cambiare gli eventi
Supponiamo che la libreria di classi includa un'interfaccia grafica della classe PictWindow che mostra la foto alla finestra:
Classe PictWindow (
Immagine dell'immagine;
pubblico:
riverniciatura del vuoto virtuale () (gt_draw_pict (immagine);)
...
};
Vorremmo sovrapporre un piccolo rettangolo in un'area specifica dell'immagine. A questo scopo, possiamo provare a sottoclasse PictWindow:
Retto retto;
ridipingere il vuoto virtuale () (gt_draw_rect (rect);)
};
Sfortunatamente, quando istanziamo OvWindow, quindi vedremo solo un rettangolo in una finestra vuota e nessuna immagine. Dal momento OvWindow :: ridisegna () sovrascrive PictWindow :: ridipingere (), l'ultima funzione non verrà chiamata quando la finestra dovrebbe essere renderizzata. dovevamo renderci conto OvWindow Così:
Classe OvWindow: PictWindow pubblica (
Retto retto;
virtual void repaint () (PictWindow :: repaint (); gt_draw_rect (rect);)
pubblico:
OvWindow (vuoto): PictWindow () ()
};
Costruttore OvWindow si propone di sottolineare che il metodo OvWindow :: ridisegna () dovrebbe essere rinviato alla superclasse come fanno i costruttori. Infatti, il costruttore dell'oggetto derivato chiama il costruttore dell'oggetto corrispondente dall'inizio. repaint() dovrebbe rinviare al suo genitore: metodo nella classe base che lo sovrascrive.
In sintesi: scarsa compatibilità C++/GUI
C++ è stato progettato per essere un linguaggio "statico":
- con tracciamento dei token
- controllo del tipo statico
- con gerarchie di classi statiche
- niente raccolta differenziata
- con un sistema di messaggi senza gerarchie di compilazione definite
Oggetti della GUI:
- oggetti dinamici caratteristici, e spesso unici
- tendono a vivere ben oltre il quadro in cui sono stati creati
- le gerarchie sono determinate in gran parte dai flussi di eventi e dalle loro posizioni piuttosto che dall'ereditarietà delle classi
- le gerarchie vengono create e distrutte in fase di esecuzione, spesso in risposta ad azioni imprevedibili dell'utente
C++ non è destinato a supportare la messaggistica dinamica e la protezione del trasferimento (tranne eccezioni). Tutto ciò porta alla duplicazione degli strumenti grafici e delle funzionalità del gestore delle finestre, alla proliferazione del codice, all'uso di funzioni non sicure e all'abbandono di molti dei punti di forza del C++.
conclusioni
Naturalmente, tutti questi "stracci" non sono fatali. Il C++ è un linguaggio versatile e potente e quindi in grado di esprimere tutti i possibili algoritmi di calcolo. Pertanto, se l'applicazione richiede funzioni dinamiche come quelle che si trovano in Tcl / Tk, Schema / Tk, Post scriptum e simili; usando C++ puoi sempre fare qualcosa seguendo il loro esempio. D'altra parte, perché non utilizzare una lingua in cui tutti questi tratti sono presenti?
C++ è uno dei linguaggi di programmazione più potenti e richiesti. Ogni giorno vengono scritte centinaia di applicazioni su di esso, spesso utilizzando la GUI. Tuttavia, lavorare con la grafica non è sempre conveniente per il programmatore: in questo caso vengono utilizzate librerie grafiche già pronte. Renderanno lo sviluppo della parte grafica delle applicazioni il più veloce e conveniente possibile.
SFML
Qt
Cocos2D-X è una libreria multipiattaforma progettata per semplificare lo sviluppo di giochi per dispositivi mobili. Supporta tutte le stesse piattaforme di Qt. Tra i vantaggi, vale la pena notare la disponibilità, la facilità d'uso e la creazione di un game designer separato basato sulla libreria Cocos Creator. Nella lista dei giochi basati sul motore c'è il famosissimo BADLAND, che funziona su tutte le piattaforme disponibili.
Qualcos'altro
Se hai bisogno di lavorare con la grafica e l'animazione in grandi volumi durante la creazione di un gioco, allora è meglio usare Unity invece di Cocos2D-X. Unity ha la capacità di integrarsi perfettamente con strumenti come Photoshop, Maya o Blender. In Cocos2D-X, tutta la grafica viene aggiunta esternamente e referenziata dal codice.
Non ci sono lezioni su questa libreria in Runet, ma c'è un eccellente corso in inglese dagli sviluppatori.
Juce
Forse una delle librerie grafiche più famose. GTK+ è un framework grafico ampiamente utilizzato in molti sistemi. È stato originariamente concepito come un componente di GIMP, ma nei 20 anni trascorsi dalla prima versione stabile ha trovato impiego in centinaia di altre applicazioni.
Ora GTK + è un framework grafico a tutti gli effetti, non inferiore allo stesso QT. Supporta vari linguaggi di programmazione e continua ad evolversi.
Qualcos'altro
Un tempo, la libreria veniva creata come alternativa a Qt, che era a pagamento. GTK+ è uno dei pochi framework che supportano il linguaggio C. La libreria è multipiattaforma, ma si ritiene che i programmi su Linux sembrino più nativi che su Windows o Mac (GTK+ è ben supportato anche su KDE). È interessante notare che, a causa di alcuni problemi multipiattaforma, Wireshark è passato a Qt.
Un esempio del primo programma può essere visualizzato su Wikipedia.
Altri articoli interessanti sul C++ possono essere trovati qui.
Conclusione
Sopra sono le tecnologie più popolari per lavorare con la GUI, non solo in C ++, ma a volte in altre lingue (ad esempio Qt e GTK +). Tuttavia, dovresti sempre tenere in considerazione le peculiarità di una particolare tecnologia. Annota un elenco delle funzioni della tua applicazione, rileggi le descrizioni di tutte le librerie e i framework e solo dopo scegli ciò che è veramente adatto al progetto.
Ministero dell'Istruzione e della Scienza della Federazione Russa
Istituto di istruzione di bilancio dello Stato federale
formazione professionale superiore
"OLIO DI STATO UFA
UNIVERSITÀ TECNICA"
Dipartimento di Informatica e Ingegneria Cibernetica
Creare un'applicazione di interfaccia utente grafica in Microsoft Visual Studio 2010
Guida allo studio
per esercitazioni di laboratorio e pratiche
con gli studenti
230100 (09.03.01) "Informatica e Ingegneria Informatica"
Il sussidio didattico contiene informazioni teoriche, compiti pratici e di laboratorio del corso "Programmazione".
Il manuale è rivolto ai docenti della disciplina, oltre che agli studenti della direzione: 230100 "Informatica e tecnologie informatiche".
Redatto da: Gabdullina A.A., art. docente del dipartimento. VTIK
Druzhinskaya E.V., art. docente del dipartimento. VTIK
Revisore: Filippov V.N., candidato di scienze tecniche, professore associato del dipartimento. VTIK.
1.Informazioni teoriche 4
1.1. Concetti di base 4
1.2. Presentazione di un'applicazione Windows Form in Microsoft Visual Studio 2010 4
1.3. Controllo della forma 7
1.5. Funzione MessageBox 9
1.6. Controllo TextBox 10
2. Un compito pratico. Presentazione di un'applicazione Windows Form in Microsoft Visual Studio 2010 12
2.1. Quadro di valutazione per il lavoro svolto 12
2.2. Ordine di lavoro pratico 12
3.Laboratorio. Sviluppo di applicazioni in Microsoft Visual Studio 2010 16
3.1. Ordine di lavoro di laboratorio 16
3.2. Attività 1. Tabulare la funzione e calcolare i suoi valori nell'intervallo specificato con un passo specificato di 16
3.3. Incarichi individuali 19
3.4. Attività 2. Elaborazione di array bidimensionali 21
3.5. Incarichi individuali 27
Informazioni teoriche
1.1. Concetti basilari
L'automazione dei processi informativi è attualmente rappresentata, in primo luogo, dallo sviluppo di un'applicazione software con interfaccia grafica utente (GUI) che controlla i flussi di dati.
L'Interfaccia Grafica Utente (GUI) è un sistema di mezzi di interazione tra l'utente e il dispositivo, basato sulla presentazione di tutti gli oggetti e le funzioni del sistema a disposizione dell'utente sotto forma di componenti grafici dello schermo (finestre, pulsanti, barre di scorrimento, eccetera.).
Molto spesso, gli elementi dell'interfaccia nella GUI sono implementati sulla base di metafore e riflettono il loro scopo e le loro proprietà, il che rende più facile per gli utenti inesperti comprendere e padroneggiare i programmi. Pertanto, il lavoro dell'utente viene svolto con maschere contenenti oggetti di controllo e barre degli strumenti con pulsanti di azione per l'elaborazione.
Un'interfaccia utente grafica standard deve soddisfare una serie di requisiti:
Mantenere la tecnologia informatica del lavoro dell'utente con il prodotto software;
Focus sull'utente finale che comunica con il programma a livello di interazione esterna;
Soddisfare il principio dei "sei", quando non sono inclusi più di 6 concetti in una barra dei menu, ognuno dei quali contiene non più di 6 opzioni;
mantenere uno scopo standardizzato degli oggetti grafici e, se possibile, la loro posizione sullo schermo.
Nella programmazione orientata agli oggetti, ci occupiamo di classi e oggetti. Gli oggetti sono tipi di dati compositi: combinano più valori in una singola unità e ci consentono di scrivere e memorizzare quei valori per nome. In altre parole, un oggetto è una raccolta non ordinata di proprietà, ciascuna con un nome e un valore. I valori denominati contenuti in un oggetto possono essere di tipo primitivo, come numeri o stringhe, o altri oggetti.
Quando si sviluppano applicazioni non console, il concetto di base è Form.
Un form è un contenitore per posizionare i controlli dell'ambiente di sviluppo.
Proprietà: la possibilità di accedere alle informazioni memorizzate in questo elemento.
I metodi sono un insieme di azioni che un oggetto può eseguire.
Un evento è un'azione riconosciuta da un oggetto (ad esempio, un clic del mouse, la pressione di un tasto) per la quale è possibile programmare una risposta, ad es. la reazione dell'oggetto a un evento che si è verificato.