| 
 | |||||||
| 
 | 
|  | 
|  | 
|  | Strumenti | 
|  21-01-2013, 14:48 | #1 | 
| Member Iscritto dal: Jul 2006 
					Messaggi: 206
				 | 
				
				[JAVA] Aiutino con Swing e Threads
			 
		Mi appello agli utenti che hanno partecipato a questa discussione: http://www.hwupgrade.it/forum/showthread.php?t=2038842   Mi sembrano abbastanza esperti nell'argomento e credo che possano aiutarmi. Il discorso mi è stato molto utile ma siccome necessito di accelerare i tempi non posso approfondire da solo l'argomento ed ho bisogno di qualche consiglio pratico per il mio caso che è un po più articolato. Cerco di farla breve. Sto creando il gioco briscola con interfaccia grafica. Ogni volta che l'utente gioca (clicca sulla carta) ovviamente c'è la logica che fa i suoi calcoli e la grafica che si aggiorna. Ho problemi tecnici con l'aggiornamento della grafica. Sfruttando gli esempi postati nella discussione che ho linkato ho scritto questo ascoltatore per i pulsanti (le carte) del giocatore umano: Codice: package gui;
import gui.GuiPartita;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.SwingUtilities;
import singleplayer.Partita;
public class MyListenerGiocatore implements ActionListener {
	private GuiPartita gp;
	private Partita p;
	
	public MyListenerGiocatore(GuiPartita gp, Partita p) {
		this.gp = gp;
		this.p = p;
	}
	
	public void actionPerformed(ActionEvent event) {
		computazione(gp,event);
	}
	
	private void computazione(final GuiPartita gp, final ActionEvent e) 
	{
	    Runnable computazione = new Runnable() {
	        @Override
	        public void run() {
	        	//calcolo
	        	if(e.getSource().equals(gp.primaCartaGiocatore)) {
	    			System.out.println("Il giocatore gioca la carta: " + p.getGiocatore().getPrimaCarta() + "\n");
	    			p.setStato(1);
	    			p.interfacciamentoUtente(1);
	    		}
	    		
	    		if(e.getSource().equals(gp.secondaCartaGiocatore)) {
	    			System.out.println("Il giocatore gioca la carta: " + p.getGiocatore().getSecondaCarta() + "\n");
	    			p.setStato(1);
	    			p.interfacciamentoUtente(2);
	    		}
	    		
	    		if(e.getSource().equals(gp.terzaCartaGiocatore)) {
	    			System.out.println("Il giocatore gioca la carta: " + p.getGiocatore().getTerzaCarta() + "\n");
	    			p.setStato(1);
	    			p.interfacciamentoUtente(3);
	    		}
	            // qui ha finito: accoda evento grafico
	            SwingUtilities.invokeLater(new Runnable()
	            {
	                @Override
	                public void run() {
	                	gp.aggiornaGrafica(); 
	                	gp.repaint();
	                }
	            });
	        }
	    };
	    (new Thread(computazione)).start();
	}
}correttamente solo quando è l'umano a giocare. Deve aggiornarsi anche quando è il computer a giocare e lo fa in automatico. Come risolvo questo piccolo problema? C'è anche il caso particolare della fine della partita. Da qualche parte devo controllare se la partita è ancora in corso, e se finisce aprire una nuova finestra che mostra il risultato. Può essere un'azione svolta in background utilizzando un worker thread? Vi prego un piccolo aiuto, grazie   Ultima modifica di Groove89 : 23-01-2013 alle 09:11. | 
|   |   | 
|  22-01-2013, 16:38 | #2 | 
| Member Iscritto dal: Jul 2006 
					Messaggi: 206
				 | 
		Ok la discussione ha spaventato    Facciamo così, cerco di essere molto più specifico. Logica --> classe Partita. Grafica --> classe GuiPartita. GuiPartita prende un'istanza di Partita nel costruttore. Il "motore" della logica che muove il tutto è dato da questo codice presente nella classe Partita: Codice: private void start() {
		
		/* Controlla turno e stato del gioco dell'utente
         * e si ramifica in 4 possibili situazioni
         */
		
        /* turno PC */
        if(isTurnoPc()) {
            /* user non ha giocato (inizio della mano) */
            if(!userHavePlayed) {
                giocoPcScarta();
                System.out.println("E' il turno del giocatore.\n");
            }
            /*user ha già risposto al gioco pc: calcolo punti e vincitore*/
            else {
                fineMano();
            }
        }
        
        /* turno user */
        else {
            /* user non ha giocato (inizio della mano) */
            if(!userHavePlayed) {
                /* non accade nulla
                 * serve il gioco dell'utente
                 */        
            }
            
            /* user ha giocato e attende risposta pc */
            else {
                giocoPcRisposta();   /* risposta pc */
                fineMano();          /* punti e vincitore */
            }            
        }
    }valori 0,1,2,3,4,5. Stato 0 = Sta iniziando la nuova mano. Stato 1 = Ha giocato il computer. Stato 2 = Hanno giocato sia computer che giocatore. Prima il computer e poi il giocatore. Stato 3 = Il giocatore ha giocato. Stato 4 = Hanno giocato sia computer che giocatore. Prima il giocatore e poi il computer. Stato 5 = Fine della partita. Per aggiornare lo stato di volta in volta prenderei il codice di sopra e lo modificherei così: Codice: private void start() {
	stato = 0;
		/* Controlla turno e stato del gioco dell'utente
         * e si ramifica in 4 possibili situazioni
         */
		
        /* turno PC */
        if(isTurnoPc()) {
            /* user non ha giocato (inizio della mano) */
            if(!userHavePlayed) {
                giocoPcScarta();
                stato = 1;
                System.out.println("E' il turno del giocatore.\n");
            }
            /*user ha già risposto al gioco pc: calcolo punti e vincitore*/
            else {
                fineMano();
                stato = 2;
            }
        }
        
        /* turno user */
        else {
            /* user non ha giocato (inizio della mano) */
            if(!userHavePlayed) {
                /* non accade nulla
                 * serve il gioco dell'utente
                 */        
            }
            stato = 3;
            /* user ha giocato e attende risposta pc */
            else {
                giocoPcRisposta();   /* risposta pc */
                fineMano();          /* punti e vincitore */
                stato = 4;
            }            
        }
    }La grafica deve poter controllare ciclicamente lo stato della Partita e vedere in che stato si trova. Questo deve avvenire senza bloccare la grafica, quindi usando edt o worker thread o non so cosa xD. Farei una cosa del tipo (non so come e dove): Codice: 	public void checkPartita() {
		while(partita.inPartita()) {
			if(stato == 0) {
				aggiornaGrafica0();
			}
			if(stato == 1) {
				aggiornaGrafica1();
			}
			if(stato == 2) {
				aggiornaGrafica2();
			}
			if(stato == 3) {
				aggiornaGrafica3();
			}
			if(stato == 4) {
				aggiornaGrafica4();
			}
			if(stato == 5) {
				aggiornaGrafica5;
			}
		}
	}  | 
|   |   | 
|  22-01-2013, 22:27 | #3 | |
| Senior Member Iscritto dal: Nov 2005 
					Messaggi: 2777
				 | 
		Botte. No scherzo, ma non capisco esattamente qual è il problema. Senza entrare nel dettaglio, nel primo post hai scritto che riesci ad aggiornare la grafica quando è il giocatore a giocare ma non quando è il computer... non capisco perché. Vedendo il secondo post sembra che non sai quando dire al computer: "gioca tu". Beh, è semplice, dopo che il giocatore ha giocato no? D'altra parte dal codice che hai scritto è chiaro che il computer gioca if(userHavePlayed). Se invece inizia a giocare il computer, farà la prima mossa all'inizio del gioco e poi adotterai la stessa logica: appena il giocatore ha giocato, il computer fa la sua mossa. L'idea che Quote: 
 | |
|   |   | 
|  22-01-2013, 23:39 | #4 | 
| Member Iscritto dal: Jul 2006 
					Messaggi: 206
				 | 
		Forse non sono stato molto chiaro   La logica funziona, il computer gioca, il giocatore gioca, riesco a svolgere una partita (tranne la fine che devo ancora gestire bene). Il mio problema primario è come far comunicare la grafica e la partita. L'interattività è la cosa che mi sta facendo uscire di testa   La grafica non può essere aggiornata da dentro la classe stessa quindi ho letto ieri dell'event dispatch thread e del worker thread che usati in modo opportuno permettono di gestire ciò che mi serve senza compromettere la grafica stessa. Questa strada andrebbe bene o il tuo consiglio di usare questo pattern observer (che ho già sentito accennare) è più di un consiglio? Comunque devo riprecisare che la grafica prende un'istanza di partita. Ho il dubbio che si debba fare al contrario, ossia avviare la grafica dalla classe partita, è così? Sono riuscito ad aggiornare in modo poco carino la grafica quando gioca il giocatore perché quando deve giocare il giocatore la logica è ferma ed in attesa. Lo scegliere una carta equivale all'attivazione dell'actionListener relativo che sblocca la logica e aggiorna la grafica utilizzando proprio l'event dispatch thread. Il computer gioca in modo autonomo, per questo non posso fare la stessa identica cosa. Ultima modifica di Groove89 : 22-01-2013 alle 23:45. | 
|   |   | 
|  23-01-2013, 09:31 | #5 | 
| Senior Member Iscritto dal: Oct 2007 Città: Padova 
					Messaggi: 4131
				 | 
		@Groove89: la tua soluzione al post #2 secondo me è valida in questo caso, perchè hai solo 6 stati da gestire. Se hai letto bene il vecchio post che citavi all'inizio (e soprattuto il tutorial su Swing di PGI-Bis che ho in firma) non avrai problemi. Devi solo stare attento in quale thread fai cosa: - mutazioni di componenti grafiche --> EDT (SwingUtilities.invokeLater o invokeAndWait a seconda dei casi per inserire delle istruzioni nella event queue). - tutto il resto --> thread non EDT (il "main" thread più eventuali altri thread nuovi). L'importante è che, leggendo e scrivendo il tuo codice, tu sappia dire senza incertezze quale metodo viene eseguito in quale thread. 
				__________________ As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) | 
|   |   | 
|  23-01-2013, 10:15 | #6 | 
| Member Iscritto dal: Jul 2006 
					Messaggi: 206
				 | 
		Stavo giusto approfondendo ora il pattern observer e devo dire che mi piace veramente tanto, il codice guadagnerebbe eleganza e andrei a disaccoppiare per bene grafica e logica   Inoltre espanderò questo gioco in futuro aggiungendo una chat e il funzionamento in lan/rete quindi forse è meglio applicare fin da subito il pattern observer. @banryu79 Penso che comunque devo andare ad utilizzare anche l'edt e cose varie unite al pattern observer giusto? Sono costretto. In particolare a me la classe GuiPartita estende JFrame ed implementa Observer, quindi avrà il metodo public void update(Observable obs, Object arg) che in base al tipo di notifica ricevuta dalla Partita (che implementa Observable) aggiorna la grafica. Per aggiornare la grafica devo usare l'edt. Sinceramente ho già provato ad aggiornare la grafica invocando invokeAndWait (creando un nuovo oggetto Runnable ecc.. ecc..) ma ho avuto una bella eccezione >.< Comunque, è questa la strada giusta almeno?  L'unica cosa che devo ancora capire bene è se la GuiPartita deve o non deve prendere la Partita nel costruttore e se è la Partita che deve avviare la GuiPartita. Aggiornamento: Sto lavorando da solo sempre in attesa di consigli ed ho cambiato un po l'impostazione visto che secondo me era corretta. La mia finestra principale (per avviare una nuova partita contro il pc oppure online) avvia la Gui a cui passa i Giocatori. La Gui a sua volta avvia una partita a cui passa i Giocatori. Sembra funzionare. Per completezza riporto i pezzetti di codice interessanti: Avvio dalla finestra principale Codice: ...
record = new RecordClassifica(nome,0,0,0);
					classifica1.aggiungiRecord(record);
					//creo i giocatori
					Giocatore a = new Giocatore(nome);
					Giocatore b = new GiocatoreElettronico("Computer");
					//Avvio la partita
					GuiPartita gp = new GuiPartita("JBriscola 0.1",a,b,record);
					this.setVisible(false);
...Codice: ...
private Partita partita;
//Players and Record
	private Giocatore giocatore;
	private GiocatoreElettronico computer;
	private RecordClassifica record;
//costruttore
public GuiPartita(String titolo, Giocatore g, Giocatore c, RecordClassifica r) {
      super(titolo);
		
		this.giocatore = g;
		this.computer = (GiocatoreElettronico)c;
		this.record = r;
		
		partita = new Partita(giocatore,computer,record);
		partita.addObserver(this);
}
//Fuori dal costruttore..
	//Update Graphics Method
	public void update(Observable obs, Object obj) {
	
		MsgObserver msg = (MsgObserver)obj;
		//Da completare con tutti i thread relativi alle swing..
	} Questa discussione può essere utile a molti utenti! ^^ Ah ps, ho creato questa classe per i messaggi che la classe Partita può inviare alla grafica. Codice: package singleplayer;
public class MsgObserver {
	
	public final static int START = 0;        
	public final static int PC_GIOCATO = 1;
	public final static int TUTTI_GIOCATO = 2;
	public final static int USER_GIOCATO = 3;
	public final static int FINE = 4;
	
	public int code;
	public Object msg;
	
	public MsgObserver(int code, Object msg) {
		this.code = code;
		this.msg = msg;
	}
}Ultima modifica di Groove89 : 23-01-2013 alle 13:53. | 
|   |   | 
|   | 
| Strumenti | |
| 
 | 
 | 
Tutti gli orari sono GMT +1. Ora sono le: 06:41.









 
		 
		 
		 
		






 
  
 



 
                        
                        










