Calcolatrice con eventi java

di il
10 risposte

Calcolatrice con eventi java

Volevo chiedere qualche consiglio su come poter migliorare il codice
Questo è il codice relativo al main
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//la mia calcolatrice è un jframe(per polimorfismo) quindi siccome estendo la classe posso applicare tutti i metodi di jframe!!!
class Calcolatrice extends JFrame {
	public JButton zero,uno,due,tre,quattro,cinque,sei,sette,otto,nove,div,molt,som,sotr,virgola,segno,uguale,radice,percent,definire,cancellaC,cancellaCE;
	public JLabel etichetta;
	public String cont = "";
	public double accumulatore = 0;
	public double salvauno=0;
	public double totale;
	public Object o;
	//inserire una variabile temporanea che contiene il valore attuale prima dell'eventuale operazione
	//public seconda,prima;
	//costruttore
	public Calcolatrice() {
		super("Calcolatrice"); //invoca costruttore di JFrame
		ActionListener asc = new Event(this);
		this.setSize(320,300);// il this si riferisce all'oggetto corrente ossia la calcolatrice
		this.setMinimumSize(new Dimension(320,300));
		this.setMaximumSize(new Dimension(500,500));
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setResizable(true);
		this.inizializzaGUI();	
		this.zero.addActionListener(asc);
		this.uno.addActionListener(asc);
		this.due.addActionListener(asc);
		this.tre.addActionListener(asc);
		this.quattro.addActionListener(asc);
		this.cinque.addActionListener(asc);
		this.sei.addActionListener(asc);
		this.sette.addActionListener(asc);
		this.otto.addActionListener(asc);
		this.nove.addActionListener(asc);
		this.som.addActionListener(asc);
		this.uguale.addActionListener(asc);
		this.molt.addActionListener(asc);
		this.div.addActionListener(asc);
		this.sotr.addActionListener(asc);
		this.cancellaC.addActionListener(asc);
		this.radice.addActionListener(asc);
		this.setVisible(true);
	} 
	public void inizializzaGUI() {
		Container c = this.getContentPane(); //il this è un riferimento all'oggetto di tipo JFrame
		c.setLayout(new GridLayout(6,1));
		JPanel tasti3; //pannello secondario per i tasti
		JPanel tasti4;
		JPanel tasti5;
		JPanel tasti6;
		JPanel cancella; //pannello secondario per cancellare
		// costruzione dei tre pannelli col rispettivo layout
		tasti3 = new JPanel(new GridLayout(1,5));
		tasti4 = new JPanel(new GridLayout(1,5));
		tasti5 = new JPanel(new GridLayout(1,5));
		tasti6 = new JPanel(new GridLayout(1,5));
		cancella = new JPanel(new GridLayout(1,2));
		//assegnazione componenti 
		etichetta = new JLabel("0");
		cancellaC = new JButton("C");
		cancellaCE = new JButton("CE");
		zero = new JButton("0");
		uno = new JButton("1");
		due = new JButton("2");	
		tre = new JButton("3");
		quattro = new JButton("4");
		cinque = new JButton("5");
		sei = new JButton("6");
		sette = new JButton("7");
		otto = new JButton("8");
		nove = new JButton("9");
		div = new JButton("/");
		molt = new JButton("*");
		som = new JButton("+");
		sotr = new JButton("-");
		virgola = new JButton(".");
		segno = new JButton("+/-");
		uguale = new JButton("=");
		radice = new JButton("sqrt");
		percent = new JButton("%");
		definire = new JButton("1/x");
		//aggiunta dei vari componenti
		cancella.add(cancellaCE);
		cancella.add(cancellaC);
		tasti3.add(sette);
		tasti3.add(otto);
		tasti3.add(nove);
		tasti3.add(div);
		tasti3.add(radice);
		tasti4.add(quattro);
		tasti4.add(cinque);
		tasti4.add(sei);
		tasti4.add(molt);
		tasti4.add(percent);
		tasti5.add(uno);
		tasti5.add(due);
		tasti5.add(tre);
		tasti5.add(sotr);
		tasti5.add(definire);
		tasti6.add(zero);
		tasti6.add(segno);
		tasti6.add(virgola);
		tasti6.add(som);
		tasti6.add(uguale);
		//aggiunta dei vari pannelli al ContentPane
		c.add(etichetta);
		c.add(cancella);
		c.add(tasti3);	
		c.add(tasti4);
		c.add(tasti5);
		c.add(tasti6);
	}
	public void mostrazero() {
		etichetta.setText(this.cont+"0");
		this.cont = this.cont+"0";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostrauno() {
		etichetta.setText(this.cont+"1");
		this.cont = this.cont+"1";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostradue() {
		etichetta.setText(this.cont+"2");
		this.cont = this.cont+"2";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostratre() {
		etichetta.setText(this.cont+"3");
		this.cont = this.cont+"3";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostraquattro() {
		etichetta.setText(this.cont+"4");
		this.cont = this.cont+"4";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostracinque() {
		etichetta.setText(this.cont+"5");
		this.cont = this.cont+"5";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostrasei() {
		etichetta.setText(this.cont+"6");
		this.cont = this.cont+"6";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostrasette() {
		etichetta.setText(this.cont+"7");
		this.cont = this.cont+"7";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostraotto() {
		etichetta.setText(this.cont+"8");
		this.cont = this.cont+"8";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void mostranove() {
		etichetta.setText(this.cont+"9");
		this.cont = this.cont+"9";
		this.accumulatore = Integer.parseInt(this.cont);
	}
	public void operazioni(Object t) {  //vale per qualsiasi operazione;
		etichetta.setText("0");
		this.cont = "";
		salvauno = totale+this.accumulatore;
		this.accumulatore = 0;
		o = t;
	}
	public void calcola() {
		if(o==this.som) {
			totale = salvauno+this.accumulatore;
			etichetta.setText(String.valueOf(totale));
		}
		else if (o==this.molt) {
			totale = salvauno*this.accumulatore;
			etichetta.setText(String.valueOf(totale));
		}
		else if (o==this.div) {
			totale = salvauno/this.accumulatore;
			etichetta.setText(String.valueOf(totale));
		}
		else if (o==this.sotr) {
			totale = salvauno-this.accumulatore;
			etichetta.setText(String.valueOf(totale));
		}
		else if (o==this.radice) {
			totale = Math.sqrt(this.accumulatore);
			etichetta.setText(String.valueOf(totale));
		}
		this.accumulatore=0;
	}
	public void azzera() {
		etichetta.setText("0");
		this.cont="";
		this.accumulatore = 0;
		this.salvauno = 0;
		this.totale = 0;
	}
	public static void main(String[] args) {
		Calcolatrice c = new Calcolatrice(); //per polimorfismo posso anche fare JFrame c =...
	}
}
Mentre questo è il codice relativo alla gestione degli eventi
import java.awt.event.*;
class Event implements ActionListener {
	//l'ascoltatore deve accedere all'applicazione
	private Calcolatrice pib;
	//inizializzo l'oggetto Listener
	public Event(Calcolatrice c) {
		this.pib = c;
	}
	//capisce quale evento accade e se accate tale evento fa partire il metodo
	public void actionPerformed(ActionEvent e) {
		if	(e.getSource()==this.pib.zero)
			this.pib.mostrazero();
		else if (e.getSource()==this.pib.uno)	
			this.pib.mostrauno();
		else if (e.getSource()==this.pib.due)
			this.pib.mostradue();
		else if (e.getSource()==this.pib.tre)
			this.pib.mostratre();
		else if (e.getSource()==this.pib.quattro)
			this.pib.mostraquattro();
		else if (e.getSource()==this.pib.cinque)
			this.pib.mostracinque();
		else if (e.getSource()==this.pib.sei)
			this.pib.mostrasei();
		else if (e.getSource()==this.pib.sette)
			this.pib.mostrasette();
		else if (e.getSource()==this.pib.otto)
			this.pib.mostraotto();
		else if (e.getSource()==this.pib.nove)
			this.pib.mostranove();
		else if (e.getSource()==this.pib.som || e.getSource()==this.pib.molt || e.getSource()==this.pib.div || e.getSource()==this.pib.sotr || e.getSource()==this.pib.radice)
			this.pib.operazioni(e.getSource());
		else if (e.getSource()==this.pib.uguale)
			 this.pib.calcola();
		else if (e.getSource()==this.pib.cancellaC)
			this.pib.azzera();
	}
}
Più che altro la calcolatrice funziona solo non capisco perchè se eseguo in sequenza operazioni di moltiplicazione e divisione(sfruttando la proprietà associativa) non funziona bene tipo 6*4*2=48 per le moltiplicazioni e divisioni devo fare le operazioni due a due(per esempio 6*4 poi premere uguale = 24 e poi moltiplicare 24 per 2, e quindi non posso fare direttamente 6*4*2=48, mentre con addizione e sottrazione si), poi non capisco perchè se eseguo 3+2*5=13 non funziona bene...
Inoltre nel main posso fare Calcolatrice c = new Calcolatrice(); ma anche JFrame c = new Calcolatrice(); per il polimorfismo?
Inoltre non capisco perchè nel costruttore Calcolatrice(), posso fare ActionListener asc = new Event(this); come parametro gli passo l'oggetto corrente, ossia la calcolatrice per inizializzare il listener in quanto deve poter accedere alla mia applicazione, ma non capisco perchè Event sia di tipo ActionListener...
Grazie per gli eventuali consigli

10 Risposte

  • Re: Calcolatrice con eventi java

    Fab996 ha scritto:


    Volevo chiedere qualche consiglio su come poter migliorare il codice
    Il codice sarebbe enormemente da migliorare come stile, struttura ed eliminando tutte le ripetizioni fatte. In questi casi bisogna cercare di "intravedere" subito cosa c'è di diverso e cosa di uguale.

    Fab996 ha scritto:


    Più che altro la calcolatrice funziona solo non capisco perchè se eseguo in sequenza operazioni di moltiplicazione e divisione(sfruttando la proprietà associativa) non funziona bene tipo 6*4*2=48 per le moltiplicazioni e divisioni devo fare le operazioni due a due(per esempio 6*4 poi premere uguale = 24 e poi moltiplicare 24 per 2, e quindi non posso fare direttamente 6*4*2=48, mentre con addizione e sottrazione si), poi non capisco perchè se eseguo 3+2*5=13 non funziona bene...
    Non ho provato il codice ... (non ho tempo ora) ma se c'è qualcosa che non va nella "logica" d'uso è appunto ... una questione di logica applicativa che non va.

    Fab996 ha scritto:


    Inoltre nel main posso fare Calcolatrice c = new Calcolatrice(); ma anche JFrame c = new Calcolatrice(); per il polimorfismo?
    Sì.

    Fab996 ha scritto:


    Inoltre non capisco perchè nel costruttore Calcolatrice(), posso fare ActionListener asc = new Event(this); come parametro gli passo l'oggetto corrente, ossia la calcolatrice per inizializzare il listener in quanto deve poter accedere alla mia applicazione, ma non capisco perchè Event sia di tipo ActionListener...
    Se Event non implementasse ActionListener non potresti "registrare" la istanza di Evento presso tutti i pulsanti. Tutti quei

    this.xxxxxx.addActionListener(asc);
  • Re: Calcolatrice con eventi java

    Grazie mille per la risposta
    Il codice sarebbe enormemente da migliorare come stile, struttura ed eliminando tutte le ripetizioni fatte. In questi casi bisogna cercare di "intravedere" subito cosa c'è di diverso e cosa di uguale.
    So che potevo organizzare meglio i bottoni utilizzando un ArrayList inoltre che dovevo utilizzare il Event Dispatch Thread, ma devo ancora studiarlo. Poi cosa altro posso migliorare?
    Non ho provato il codice ... (non ho tempo ora) ma se c'è qualcosa che non va nella "logica" d'uso è appunto ... una questione di logica applicativa che non va.
    Si, sarà qualche variabile non messa al punto giusto... Semmai quando hai un attimo se puoi fammi sapere:)
    Se Event non implementasse ActionListener non potresti "registrare" la istanza di Evento presso tutti i pulsanti. Tutti quei

    this.xxxxxx.addActionListener(asc);
    Mh, però non capisco perchè devo fare ActionListener asc = new Event(this), non dovrebbe essere Event asc = new Event(this)? O è presente qualche fenomeno di polimorfismo che trascuro?
  • Re: Calcolatrice con eventi java

    Fab996 ha scritto:


    So che potevo organizzare meglio i bottoni utilizzando un ArrayList inoltre che dovevo utilizzare il Event Dispatch Thread, ma devo ancora studiarlo. Poi cosa altro posso migliorare?
    No, non è tanto questione di ArrayList per i pulsanti.

    Hai usato un listener che è "esterno" alla classe della calcolatrice. Quindi hai dovuto "aprire" l'accesso a molte (troppe) cose:
    - campi public (altrimenti dal listener non potresti testare i pulsanti)
    - metodi public mostrazero ecc... (che altrimenti non potresti invocare).

    Ti sembra buono? La questione, in generale, è che la gestione (implementazione) del listener dovrebbe essere più vicina e "intima" possibile al punto in cui sono gestiti i componenti. Avere un listener esterno ha senso per certi design o quando la interazione è minima (es. si può fare tutto con il solo "source" dell'evento o poco più).

    Inoltre, come dicevo prima, un aspetto importante è quello di saper "intravedere" cosa c'è di uguale e di diverso.

    Tra:
       public void mostrazero() {
          etichetta.setText(this.cont+"0");
          this.cont = this.cont+"0";
          this.accumulatore = Integer.parseInt(this.cont);
       }
    e
       public void mostrauno() {
          etichetta.setText(this.cont+"1");
          this.cont = this.cont+"1";
          this.accumulatore = Integer.parseInt(this.cont);
       }
    e gli altri mostraXXX, cosa c'è di diverso e di uguale? Puoi generalizzare magari con un parametro? (certo che si può!)

    Inoltre tieni presente che i pulsanti hanno un "actionCommand" che è una stringa arbitraria (e non c'entra niente con il testo sul pulsante) ad uso del programmatore per farne un identificatore o una informazione. Nel caso di una calcolatrice può essere utile.
    Mh, però non capisco perchè devo fare ActionListener asc = new Event(this), non dovrebbe essere Event asc = new Event(this)? O è presente qualche fenomeno di polimorfismo che trascuro?
    Stessa cosa di prima. Ma è meglio che fissi bene il concetto, perché è così importante che se ti trascini dietro questi dubbi a lungo, non vai molto lontano ....

    La "ereditarietà" definisce una relazione di generalizzazione/specializzazione tra due classi (tipi in generale). E porta al polimorfismo, cioè al concetto basilare che un tipo può essere visto anche come uno dei tipi da cui deriva.

    class Animale { }
    class Gatto extends Animale { }
    class GattoPersiano extends Gatto { }

    Un oggetto GattoPersiano è-un (in inglese la relazione si dice "IS-A") Gatto che è-un Animale. Quindi un GattoPersiano può essere visto anche come Gatto e anche come Animale, allo stesso tempo.
    E OVUNQUE sia richiesto un oggetto di tipo es. Animale, tu puoi lecitamente passare sia un oggetto Gatto, sia un GattoPersiano.

    Se hai un metodo

    public static void provaAnimale(Animale a)

    tutti questi scenari sono validi:

    GattoPersiano gp = new GattoPersiano();
    provaAnimale(gp);

    oppure

    Gatto g = new GattoPersiano();
    provaAnimale(g);

    oppure

    Animale a = new GattoPersiano();
    provaAnimale(a);

    Cosa cambia? Ai fini di provaAnimale nulla. Il metodo "sa" solo che è un Animale. Quello che in generale conta e può fare la differenza è la "visibilità" dei metodi/campi, che dipende SOLO dal tipo "statico" del reference (in questo caso la variabile definita e il parametro).
    Se Gatto (e quindi anche GattoPersiano) ha un metodo miagola() ma Animale NON ce l'ha (ovviamente), il seguente NON funziona.

    Animale a = new GattoPersiano();
    a.miagola(); // NO

    Anche se io so che GattoPersiano ha il miagola(), il compilatore NON può vederlo né invocarlo su una variabile di tipo Animale (anche se ci assegno un GattoPersiano!). Sono le regole di Java, che è un linguaggio "tipizzato staticamente".
    Il compilatore si basa solo sul tipo "statico" del reference utilizzato nel codice per determinare cosa può accedere ed invocare.

    Nel tuo caso siccome Event NON ha metodi in più e l'unico metodo actionPerformed viene invocato polimorficamente dal framework vedendo l'oggetto solo come ActionListener, che tu abbia nel tuo sorgente:

    ActionListener asc = new Event(this);
    xyz.addActionListener(asc);

    oppure

    Event ev = new Event(this);
    xyz.addActionListener(ev);

    Non fa differenza, non per addActionListener: si aspetta un ActionListener e Event è-un ActionListener.
    Se tu nel tuo Event avessi un metodo specifico per estrarre o settare informazioni, allora solo il secondo scenario ti sarebbe utile per invocarlo (variabile Event), altrimenti con ActionListener non potresti vederlo.
  • Re: Calcolatrice con eventi java

    Grazie per la spiegazione dettagliata!
    Però una soluzione di questo tipo non sarebbe corretta vero GattoPersiano gp = new Animale(); ?
  • Re: Calcolatrice con eventi java

    Fab996 ha scritto:


    Però una soluzione di questo tipo non sarebbe corretta vero GattoPersiano gp = new Animale(); ?
    No, infatti è scorretta e illegale (sempre con la gerarchia detta prima ma pure in senso concettuale).

    Un oggetto Integer è-un Object ma un oggetto Object NON è un Integer.

    Object val = new Integer(123); // ok
    Integer val = new Object(); // NO (non compila proprio!)
  • Re: Calcolatrice con eventi java

    Ok ho capito, solo mi rimane il dubbio su ActionListener asc = new Event(); in quanto la classe Event implementa solamente ActionListener, mentre l'esempio
    class Animale{}
    class Gatto extends Animale{}
    Posso fare Animale = new Gatto() in quanto Gatto estende Animale e quindi per via del polimorfismo, però Event implementa solamente ActionListener e non la estende, quindi non essendoci fenomeni di ereditarietà non vi possono essere neanche fenomeni di polimorfismo
  • Re: Calcolatrice con eventi java

    Fab996 ha scritto:


    però Event implementa solamente ActionListener e non la estende, quindi non essendoci fenomeni di ereditarietà non vi possono essere neanche fenomeni di polimorfismo
    Sì che c'è la ereditarietà!! ActionListener è un super-tipo di Event. Quindi Event è-un ActionListener.

    Una classe estende sempre un'altra classe (se non è esplicitata, è Object implicitamente) e può implementare N interfacce.

    class MyClass extends A implements B, C

    MyClass ha 3 super-tipi: la classe A, le interfacce B e C. Sono, ripeto, super-tipi, quindi vale il polimorfismo e vale la relazione IS-A. Stop.


    P.S. Ah, e vale anche per le interfacce. Una interfaccia può estendere N altre interfacce.
  • Re: Calcolatrice con eventi java

    Ahh ma quindi quando si implementa un'interfaccia c'è anche l'ereditarietà, io pensavo vi fosse solamente quando si estende una classe...
  • Re: Calcolatrice con eventi java

    Fab996 ha scritto:


    Ahh ma quindi quando si implementa un'interfaccia c'è anche l'ereditarietà
    Certo. Se così non fosse, non potresti passare/assegnare un oggetto di tipo Event dove è richiesto un ActionListener ... e quindi tutto questo discorso non porterebbe né servirebbe a nulla.

    interface IA { }
    interface IB { }

    interface IC extends IA, IB { }

    class A { }
    class B extends A implements IC { }


    B ha 2 super-tipi diretti: A e IC
    Ma a loro volta: A estende Object e IC estende IA e IB

    Quindi dato B b = new B();

    b instanceof B
    b instanceof A
    b instanceof IC
    b instanceof IA
    b instanceof IB
    b instanceof Object

    sono tutte espressioni "true"

    Spero di non averti confuso ...
  • Re: Calcolatrice con eventi java

    Ti ringrazio, è che il fatto che quando si implementa l'interfaccia vi è anche l'ereditarietà non lo trovavo scritto da nessuna parte in maniera esplicita, avevo capito che quando si implementa un'interfaccia si danno le varie specifiche dei metodi astratti dell'interfaccia stessa, mentre appunto pensavo che l'ereditarietà vi fosse solo quando si estendeva la classe.
Devi accedere o registrarti per scrivere nel forum
10 risposte