Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Roborock Qrevo Curv 2 Flow: ora lava con un rullo
Roborock Qrevo Curv 2 Flow: ora lava con un rullo
Qrevo Curv 2 Flow è l'ultima novità di casa Roborock per la pulizia di casa: un robot completo, forte di un sistema di lavaggio dei pavimenti basato su rullo che si estende a seguire il profilo delle pareti abbinato ad un potente motore di aspirazione con doppia spazzola laterale
Alpine A290 alla prova: un'auto bella che ti fa innamorare, con qualche limite
Alpine A290 alla prova: un'auto bella che ti fa innamorare, con qualche limite
Abbiamo guidato per diversi giorni la Alpine A290, la prima elettrica del nuovo corso della marca. Non è solo una Renault 5 sotto steroidi, ha una sua identità e vuole farsi guidare
Recensione HONOR Magic 8 Lite: lo smartphone indistruttibile e instancabile
Recensione HONOR Magic 8 Lite: lo smartphone indistruttibile e instancabile
Abbiamo provato a fondo il nuovo Magic 8 Lite di HONOR, e per farlo siamo volati fino a Marrakech , dove abbiamo testato la resistenza di questo smartphone in ogni condizione possibile ed immaginabile. Il risultato? Uno smartphone praticamente indistruttibile e con un'autonomia davvero ottima. Ma c'è molto altro da sapere su Magic 8 Lite, ve lo raccontiamo in questa recensione completa.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 21-01-2013, 14:48   #1
Groove89
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();
	}
}
Ovviamente non basta perché così facendo la grafica si aggiorna
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.
Groove89 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2013, 16:38   #2
Groove89
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 */
            }            
        }
    }
L'idea che mi è venuta in mente poco fa per aggiornare la grafica di volta in volta è inserire nella classe partita una variabile stato che può assumere i
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;
            }            
        }
    }
Ovviamente nella medesima classe inserisco il metodo get per lo stato.

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;
			}
		}
	}
Potrebbe andar bene? Consigli o botte per me?
Groove89 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2013, 22:27   #3
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2787
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:
La grafica deve poter controllare ciclicamente lo stato della Partita
e vedere in che stato si trova.
E' decisamente sconsigliata, molto meglio adottare il pattern Observer, che, detto in estrema sintesi, funziona così: quando lo stato cambia, avvisa l'interfaccia grafica che quindi si aggiorna. In questo modo l'interfaccia non interroga continuamente lo stato ma lo fa solo quando è effettivamente necessario.
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2013, 23:39   #4
Groove89
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.
Groove89 è offline   Rispondi citando il messaggio o parte di esso
Old 23-01-2013, 09:31   #5
banryu79
Senior Member
 
L'Avatar di banryu79
 
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)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 23-01-2013, 10:15   #6
Groove89
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);
...
Avvio della partita (che estende observable) dalla gui (che implementa Observer):

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..
	}
Che ne dite? 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.
Groove89 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Roborock Qrevo Curv 2 Flow: ora lava con un rullo Roborock Qrevo Curv 2 Flow: ora lava con un rull...
Alpine A290 alla prova: un'auto bella che ti fa innamorare, con qualche limite Alpine A290 alla prova: un'auto bella che ti fa ...
Recensione HONOR Magic 8 Lite: lo smartphone indistruttibile e instancabile Recensione HONOR Magic 8 Lite: lo smartphone ind...
Sony WF-1000X M6: le cuffie in-ear di riferimento migliorano ancora Sony WF-1000X M6: le cuffie in-ear di riferiment...
Snowflake porta l'IA dove sono i dati, anche grazie a un accordo con OpenAI Snowflake porta l'IA dove sono i dati, anche gra...
Missione Artemis II diretta verso la Lun...
Toy Story 5 arriva al cinema: è l...
Intel cambia rotta su Linux? Nuove assun...
Samsung aggiorna Bixby con One UI 8.5: p...
L'Etiopia vieta le auto a combustione: a...
Pirateria audiovisiva: la Guardia di Fin...
Ubisoft conferma due nuovi Far Cry in sv...
Chi vincerà il Festival di Sanrem...
G42 e Cerebras portano in India un super...
Offerte aggiornate del weekend Amazon: 7...
4 MacBook Air in offerta e scende a 939€...
Chrome cambia il tuo modo di lavorare: o...
Minimo storico iPhone 17 su Amazon: 909€...
USA, incriminati tre ingegneri della Sil...
Xbox: Phil Spencer lascia dopo 38 anni, ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 21:29.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v