L'obiettivo e' realizzare in Java un'interfaccia che visualizza un grafo piano.
Un grafo piano e' descritto da:
Nota: il sistema di coordinate nel quale e' espresso il grafo e' un sistema a coordinate reali che non ha nessuna relazione coi pixel dello schermo.
L'interfaccia grafica deve fornire le seguenti funzionalita':
Procederemo per gradi:
Non occorre consegnare nulla, questo e' solo un esercizio che vi sara' utile per il progetto finale del corso.
SUGGERIMENTO:
E' molto utile programmare tenendo aperta
a fianco una finestra sul sito con il manuale on-line delle
classi Java:
http://java.sun.com/j2se/1.4.2/docs/api/index.html
L'interfaccia dovra' contenere
Come dispositivi per aprire e chiudere un grafo si possono usare, a scelta:
A scelta, per controllare lo zoom si possono usare:
Effettuare la scelta, disegnare lo schema dell'interfaccia
(che mostra dove sono collocati i vari dispositivi).
Determinare quale gerarchia di contenimento e quali layout manager
sono necessari per ottenere la configurazione voluta.
Scrivere il codice Java che ottiene l'interfaccia, per adesso nessun dispositivo reagira' ancora all'interazione con l'utente.
Il pannello in cui si disegna il grafo per adesso sara' una sotto-classe di Panel o di JPanel, dove e' ridefinita getPreferredSize per ottenere dimensioni di default non nulle (come nell'esempio ExDraw1 delle dispense). Non viene disegnato ancora nulla al suo interno.
Chiedere all'utente il nome del file usando il dispositivo predefinito Java per chiedere un file (FileDialog o JFileChooser, vedere dispense e manuale in linea di Java).
E' fornita la classe MyReader per leggere da file, tale classe ha le seguenti funzioni:
Il formato del file che contiene il grafo e' il seguente:
elemento | tipo | significato |
x0 y0 | due double | coordinate min del dominio |
deltaX deltaY | due double | ampiezze del dominio |
nv na | due interi | numero di vertici e archi |
x0 y0 x1 y1 ... |
tante coppie di double quanti i vertici | coordinate dei vertici |
a0 b0 a1 b1 ... |
tante coppie di interi quanti gli archi, un valore k identifica il k-esimo vertice nella lista di vertici precedente, dove il primo vertice e' identificato dal numero 0 |
primo e secondo estremo di ogni arco |
Esempi di grafi (il disegno esplicativo inquadra il solo dominio e ha l'asse y girato verso l'alto):
Come struttura dati per il grafo si consiglia di usare:
Schema di frammento di programma che legge un grafo, gestendo anche le eccezioni (le parti tra *** dovranno essere sostituite dai nomi delle vostre variabili):
try { MyReader rd = new MyReader(***nome del file***); ***x0*** = rd.readDouble(); ***y0*** = rd.readDouble(); ***delta x*** = rd.readDouble(); ***delta y*** = rd.readDouble(); ***numero vertici*** = rd.readInteger(); ***numero archi*** = rd.readInteger(); int i; for (i=0; i<***numero vertici***; i++) { ***x vertice i-esimo*** = rd.readDouble(); ***y vertice i-esimo*** = rd.readDouble(); } for (i=0; i<***numero archi***; i++) { ***primo estremo arco i-esimo*** = rd.readInteger(); ***secondo estremo arco i-esimo*** = rd.readInteger(); } } catch (Exception excp) { System.err.println("Error in reading: " + excp.getMessage()); }
L'area di disegno sara' una sotto-classe di pannello
dove la funzione paint (in AWT) o paintComponent (in Swing)
disegna il grafo.
Il grafo puo' essere memorizzato come attributo di questa
classe.
Esempio schematico (dove i nomi MioGrafo e MioPannello indicano la classe grafo e la classe pannello di disegno):
class MioPannello extends Panel { MioGrafo grafo; public MioPannello(MioGrafo g) { grafo = g; } public Dimension getPreferredSize() { return new Dimension(500,500); } public void paint(Graphics g) { ...... } }
Le coordinate in cui e' dato il grafo (user space o coordinate
logiche) non hanno relazione
con le coordinate della finestra (device space o coordinate fisiche).
Occorre quindi una traduzione.
La traduzione puo' essere fatta in due modi:
Nota: e' preferibile mantenere in device space le stesse proporzioni fra x e y che erano in user space. A questo scopo eseguire la stessa scalatura su x e y, usando il fattore piu' piccolo.
Sul pannello deve essere attivo un mouse motion listener che
implementi la funzione di reazione a movimento del mouse
con bottone premuto (mouseDragged)
traslando il disegno del grafo nel pannello.
L'idea e' che io aggangio la scena e la trascino nella
direzione del mouse.
A tale scopo bisogna:
Se si usa uno slider, i valori ammessi per il fattore di scala possono essere per esempio da 0 a 10, per default 1.
Se si usano bottoni, i due valori devono essere uno l'inverso dell'altro, per es. 0.5 e 2 oppure 0.8 e 1.25.
Applicare lo zoom alle coordinate proprie del grafo (user space)
prima di trasportarle nella finestra (device space).
Bisogna nell'ordine: