Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi
Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi
Con la prima rete 5G Standalone attiva in Italia, WINDTRE compie un passo decisivo verso un modello di connettività intelligente che abilita scenari avanzati per imprese e pubbliche amministrazioni, trasformando la rete da infrastruttura a piattaforma per servizi a valore aggiunto
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro punta a diventare uno dei riferimenti assoluti nel segmento dei camera phone di fascia alta. Con un teleobiettivo Hasselblad da 200 MP, una batteria al silicio-carbonio da 7500 mAh e un display da 6,78 pollici con cornici ultra ridotte, il nuovo flagship non teme confronti con la concorrenza, e non solo nel comparto fotografico mobile. La dotazione tecnica include il processore MediaTek Dimensity 9500, certificazione IP69 e un sistema di ricarica rapida a 80W
DJI Romo, il robot aspirapolvere tutto trasparente
DJI Romo, il robot aspirapolvere tutto trasparente
Anche DJI entra nel panorama delle aziende che propongono una soluzione per la pulizia di casa, facendo leva sulla propria esperienza legata alla mappatura degli ambienti e all'evitamento di ostacoli maturata nel mondo dei droni. Romo è un robot preciso ed efficace, dal design decisamente originale e unico ma che richiede per questo un costo d'acquisto molto elevato
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: 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:
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


Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi Wind Tre 'accende' il 5G Standalone in Italia: s...
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh OPPO Find X9 Pro: il camera phone con teleobiett...
DJI Romo, il robot aspirapolvere tutto trasparente DJI Romo, il robot aspirapolvere tutto trasparen...
DJI Osmo Nano: la piccola fotocamera alla prova sul campo DJI Osmo Nano: la piccola fotocamera alla prova ...
FUJIFILM X-T30 III, la nuova mirrorless compatta FUJIFILM X-T30 III, la nuova mirrorless compatta
Addio console: Just Dance Now trasforma ...
Driver Radeon Adrenalin 25.10: perch&egr...
Oltre le GPU: NVIDIA annuncia NVQLink, ...
Samsung lancia il Team Galaxy Italia per...
Magic Leap: indistinguibili dai normali ...
Aruba Cloud: trasparenza sui costi e str...
Quando il cloud si blocca e resti al fre...
Integrare per competere, la sfida digita...
Leggenda del rally e modernità: S...
La Python Software Foundation rinuncia a...
Full HD e QLED, è in offerta un TV da 32...
Honda ha rilasciato un nuovo video sul p...
Resident Evil Requiem: arriva su Switch ...
Marshall Acton III in promo su Amazon in...
2 portatili che costano poco ma vanno be...
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: 06:41.


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