Variabili globali

Vediamo come si può fare per evitare la cancellazione delle cose fatte da mouseDown. Prendiamo il programma CrociCerchiLinea.java e facciamo in modo che almeno l'ultimo punto non venga cancellato. Come si è detto, in effetti tutto viene cancellato quando la finestra è coperta. L'unica cosa che si può fare è fare in modo che i disegni fatti da mouseDown vengano ridisegnati di nuovo quando la finestra appare di nuovo.

Sappiamo che quando la finestra appare vengono eseguite le istruzioni dentro paint. Quindi, è necessario che le cose disegnate da mouseDown vengano disegnate di nuovo da paint quando la finestra diventa di nuovo visibile.

Iniziamo con un caso semplice: modifichiamo l'applet CrociCerchiLinea.java in modo che l'ultima figura disegnata da mouseDown sia permanente. Per fare questo è necessario memorizzare la posizione e forma di quest'ultima figura in modo tale che paint possa leggere questo valore, e ridisegnare la figura quando serve. Il meccanismo che abbiamo per memorizzare dati è quello delle variabili. Resta però il problema di dove dichiarare queste variabili.

Supponiamo infatti di voler memorizzare le coordinate x e y dell'ultima posizione in cui il pulsante è stato premuto. Questi due numeri sono chiaramente sufficienti per disegnare di nuovo l'ultima figura fatta. Usiamo quindi due variabili xultimo e yultimo. Il problema è che la posizione dell'ultimo click viene memorizzata dentro mouseDown, ma questi dati sono necessari a paint per poter disegnare di nuovo l'ultima figura quando la finestra diventa nuovamente visibile. Se dichiariamo queste due variabili dentro mouseDown, la procedura paint non la può usare; se le dichiariamo dentro paint allora mouseDown non ci può scrivere; dichiarare queste due variabili in entrambe le procedure non serve, dal momento che variabili in procedure diverse sono diverse (corrispondono a zone di memoria diverse) anche se hanno lo stesso nome.

Il meccanismo che si usa per permettere ai due blocchi interni a mouseDown e paint di condividere delle variabili è quello di dichiararle come variabili globali. Una variabile è globale se viene dichiarata all'interno delle parentesi graffe di class ... { ... } ma prima delle procedure (cioè prima di public boolean mouseDown). Le variabili dichiarate in questo modo si dicono appunto globali, e sono variabili che tutte le procedure possono usare. Nel nostro caso, dichiarando una variabile globale xultimo di tipo intero, sia mouseDown che paint possono accedere ad essa. In questo modo, all'interno di mouseDown possiamo memorizzare in questa variabile la coordinata x dell'ultimo punto in cui il pulsante è stato premuto, mentre all'interno di paint possiamo utilizzare il valore che è stato memorizzato in precedenza.

Per poter ripetere l'ultima figura disegnata sono chiaramente necessari due valori, che corrispondono alle due coordinate dell'ultimo punto in cui il pulsante del mouse è stato premuto. Le seguenti dichiarazioni creano due variabili globali in cui è possibile memorizzare questi valori.

import java.awt.*;

public class CrociCerchiLineaUltimo extends java.applet.Applet {

  int xultimo=-4, yultimo=-4;

        /* risponde al click del mouse */
  public boolean mouseDown(Event e, int x, int y) {

  ...
All'interno di mouseDown occorre aggiungere delle istruzioni che memorizzano i valori di x e y nelle variabili xultimo e yultimo. Le due istruzioni necessarie sono chiaramente xultimo=x e yultimo=y.

L'ultima figura deve venire poi disegnata di nuovo da paint. Per fare questo, aggiungiamo, all'interno di paint, le istruzioni che disegnano la figura appropriata alle coordinata xultimo e yultimo, che rappresentano le coordinate dell'ultimo punto in cui il pulsante del mouse è stato premuto. Il codice completo del programma CrociCerchiLineaUltimo.java è riportato qui sotto.

/*
  Disegna croci e cerchi, piu' la linea
  che li separa.
*/

import java.awt.*;

public class CrociCerchiLineaUltimo extends java.applet.Applet {

  int xultimo=-4, yultimo=-4;

	/* risponde al click del mouse */
  public boolean mouseDown(Event e, int x, int y) {
    Graphics g=getGraphics();

    if( x<=200 ) {
      g.drawLine(x,y-5,x,y+5);
      g.drawLine(x-5,y,x+5,y);
    }
    else {
      g.drawOval(x-5,y-5,10,10);
    }

    xultimo=x;
    yultimo=y;

    return true;
  }

	/* disegna la linea di separazione */
  public void paint(Graphics g) {
    g.drawLine(200,0,200,500);

    if( xultimo<=200 ) {
      g.drawLine(xultimo,yultimo-5,xultimo,yultimo+5);
      g.drawLine(xultimo-5,yultimo,xultimo+5,yultimo);
    }
    else {
      g.drawOval(xultimo-5,yultimo-5,10,10);
    }

  }
}

Va fatta una precisazione sul perchè le variabili xultimo e yultimo hanno valori iniziali -4. Si tratta di un espediente per evitare il disegno di una figura geometrica quando l'applet parte. Come si è detto, quello che sta dentro paint viene eseguito una prima volta, sempre, quando si esegue il programma (dopo che la finestra è stata creata). All'inizio il pulsante del mouse non è stato mai premuto, per cui le istruzioni di mouseDown non sono mai state eseguite. Quindi, le variabili xultimo e yultimo non contengono l'ultimo punto (semplicemente perchè non esiste un punto in cui il mouse è stato premuto).

Quando l'applet viene lanciato, si esegue la procedura paint. Questa disegna la linea verticale, e poi un cerchio o una croce. Dal momento che inizialmente le due variabili xultimo e yultimo valgono -4, la figura disegnata è fuori dall'area visibile.

Ogni volta che viene premuto il pulsante del mouse, viene disegnata una croce oppure un cerchio. Inoltre, i valori delle coordinate della posizione del cursore vengono salvate nelle variabilie xultimo e yultimo. Se si preme nuovamente il pulsante, si fa il nuovo disegno, e nelle variabili xultimo e yultimo ci si mettono le nuove coordinate. Quindi, queste variabili contengono sempre le coordinate dell'ultimo punto di click. Quando la finestra viene coperta e poi scoperta di nuovo, viene eseguita la procedura paint, che disegna di nuovo la linea verticale, e poi disegna una croce oppure un cerchio alle coordinate xultimo e yultimo. Il programma fa esattamente quello che era richiesto: se la finestra viene coperta e poi scoperta, l'ultima figura disegnata rimane.