JavaFX attesa evento da un tasto

di il
8 risposte

JavaFX attesa evento da un tasto

Salve a tutti,

sto sviluppando un programmino per giocare a carte. Stando ad implementare l'interfaccia grafica con Javafx non riesco a capire come, in base al turno di gioco, si possa scegliere una carta e restituirne il valore.

A linea di comando è semplice perché il programma attende fino a che il buffer ( BufferedReader(new InputStreamReader(System.in)) ) non riceve qualcosa, sto trovando difficoltà con la Gui.

Cioè, quando è il turno del giocatore non posso mettere un while(true) aspettando che accada un evento (pressione di un tasto(una carta) sulla gui) perché il programma va in attesa attiva e non risponde più.
Vorrei sapere se debbo implementare un meccanismo usando i thread e se potete indirizzarmi verso qualche sito idoneo.

Grazie

Qualche linea di codice:


@Override
	public Entry<Integer,CardInterface> chooseCard() {
		Entry<Integer,CardInterface>  card=null;
		
		//se viene usata la Gui java fx
		if(Coordinator.getInstance().getGuiOrNot()) {
			Coordinator.getInstance().getTurno().showCardsInHand();
			//si deve ritornare un valore preso da una tasto dalla gui
			
			//TODO
			
			
		}
		//altrimenti a linea di comando
		else {
			System.out.println("/*---turno del realplayer---*/\n");
			
			Coordinator.getInstance().getTurno().showCardsInHand().showDeck().entrySet().parallelStream().forEach(cards->
				System.out.print(cards.getKey()+")"+cards.getValue().printCard()+"\n"));
			
			System.out.println("\n/*---carte in tavola---*/\n");
			
			Dealer.getInstance().getCardTable().showDeck().entrySet().parallelStream().forEach(cards->
				System.out.print(cards.getValue().printCard() ));
			
			System.out.println("\nScegliere una carta\n");
			while(card==null) {
				card=cardExists();
			}
		}	
		return card;
	}
	
	/**Viene controllato se il dato inserito da tastiera &eacute; valido<br>
	 * e se la carta esiste nella mano del giocatore
	 * @return La carta scelta dal giocatore
	 * @throws IOException 
	 * @see {@link CardInterface}
	 * @see {@link Player}
	 * @see {@link StrategyInterface}
	 */
	private Entry<Integer,CardInterface> cardExists(){
		
		Entry<Integer,CardInterface>  card=null;
		BufferedReader tastiera=null;
		
			while(card==null) {
				try {
					tastiera=new BufferedReader(new InputStreamReader(System.in));
					card=Coordinator.getInstance().getTurno().getCardFromHand(Integer.parseInt(tastiera.readLine()));
			
				if(card==null)System.out.println("Elemento non presente,ricontrolla");
				} catch (IndexOutOfBoundsException | IOException | NumberFormatException e) {
					System.out.println("Elemento non presente,ricontrolla");
				}
			}
			
		return card;
	}
	

8 Risposte

  • Re: JavaFX attesa evento da un tasto

    federaimondi ha scritto:


    Cioè, quando è il turno del giocatore non posso mettere un while(true) aspettando che accada un evento
    No infatti, non puoi. Devi registrare dei listener per ricevere gli eventi che ti interessano (es. click su un pulsante).

    Ma credo che la tua questione principale sia più che altro fare lo "shift mentale" da una applicazione "console" (dove decidi tu esattamente QUANDO stampare qualcosa o chiedere input) a una applicazione "gui" (dove invece va tutto avanti per "eventi").
    Non è facile, lo so ... lo capisco, specialmente per chi inizia.
  • Re: JavaFX attesa evento da un tasto

    Parola chiave quindi è programmazione per eventi? Consigli al volo su siti, libri, tutorial youtube ?
  • Re: JavaFX attesa evento da un tasto

    federaimondi ha scritto:


    Parola chiave quindi è programmazione per eventi? Consigli al volo su siti, libri, tutorial youtube ?
    Cosa hai letto finora su JavaFX? Se hai una guida/tutorial/libro decente dovrebbe come minimo spiegare la gestione degli eventi.

    Banalmente per un pulsante:
    pulsante.setOnAction(e -> {
        // ... fai qualcosa alla azione sul pulsante
    });
    questo sopra è con una lambda ma puoi anche usare le solite anonymous inner class.

    La difficoltà forse maggiore, semmai, è invece "ragionare" bene per eventi.
  • Re: JavaFX attesa evento da un tasto

    Per ora lo scaricato alcuni pdf( da leggere con calma perchè è un argomento pesante).

    Principalmente ho cominciato a leggere come viene gestita la concorrenza in javafx sulla documentazione ufficiale:
    la questione è molto simile a java ma con la differenza che si prediligono i Task più che i Thread che sono praticamente dei FutureTask di java; il bello però è che è possibile eseguire metodi particolari per aggiornare i componenti della "Scene" senza dover aspettare che il Future ritorni qualcosa, quindi è possibile mettere un loop all'interno di " call() " e fare un bind alla proprietà del componente desiderato.
  • Re: JavaFX attesa evento da un tasto

    Ora però ho un altro problema, riguarda sempre l'argomento in questa ultima mia risposta, ma non di questo specifico argomento; io lo posto qua, poi se lo devo spostare lo sposto.


    Allora qui sotto c'è una semplice classe Server che dovrebbe gestire più client ( cliché di noi newbie ) : Il fatto è che la comunicazione avviene bene sulla console (con System.out.println) anche con più cliente contemporaneamente, però " updateMessage " non aggiorna il componente. come invece avviene con un unico Client connesse e senza loop in " startConnection() ";


    
    
    /**
     * Finestra del server dove vengono visualizzati tutti dati inviati dai client
     * @author feder
     *
     */
    public class ServerGuiControl{
    	
    	private ServerSocket myServerSocket=null;
    	private Socket mySocket;
    	private BufferedReader fromClient;
    	private DataOutputStream outFromServer;
    	
    	@FXML
    	public Button btnStart,btnStop;
    	
    	
    	@FXML
    	public TextArea txaChat; //elemento in esame
    
    
    	/**
    	 * Premento il pulsante si permettono le connessioni dei client
    	 * 
    	 * @throws IOException
    	 * @throws InterruptedException
    	 * @throws ExecutionException
    	 */
    	public void startConnection() throws IOException, InterruptedException, ExecutionException {
    
    			myServerSocket = new ServerSocket(6789);
    			
    			while(true){
    				//ad ogni client viene creato un nuovo Task; questo si avvia automaticamente
    				//dal costruttore grazie a un ExecutorService, per poi chimare call()
    				mySocket = myServerSocket.accept();
    				ClientConnection c=new ClientConnection(mySocket);				
    			}	
    	}
    
    	/**
    	 * Task per ogni nuova Connessione in ingresso al serverSocket
    	 * @author feder
    	 *
    	 */
    	public class ClientConnection extends Task<Void>{
    
    		private Socket clientSocket;
    		private BufferedReader in;
    		private ExecutorService myExecutor;
    		
    		public ClientConnection(Socket clientSocket) {
    			this.clientSocket=clientSocket;		
    			
    			//Si fa un bind alla proprietà del componente per poterlo aggiornare;
    			txaChat.textProperty().bind(this.messageProperty());
    			
    			//avvio del Task
    			this.myExecutor=Executors.newSingleThreadExecutor();
    			this.myExecutor.execute(this);
    		}
    		
    		@Override
    		public Void call() throws Exception {
    			updateMessage("Socket accept message...");
    			try {
    				while(true) {
    					
    					in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
    					String s=in.readLine();
    					System.out.println(s);
    					
    					updateMessage(s);//qui dovrebbe inviare i dati al componente e aggiornarlo
    					
    				}
    			}
    			catch(IOException e) {
    				e.printStackTrace();
    			}
    			return null;
    		}
    	}	
    }
    
    Qualcuno mi aiuti
  • Re: JavaFX attesa evento da un tasto

    federaimondi ha scritto:


    la questione è molto simile a java ma con la differenza che si prediligono i Task più che i Thread
    In JavaFX si possono benissimo usare direttamente i thread. L'unica cosa da ricordare è che JavaFX (similarmente a Swing) usa il paradigma del "single UI thread". C'è un solo thread che si occupa della UI e tutte le modifiche e l'accesso alla UI vanno fatte nel contesto di quel thread specifico.

    federaimondi ha scritto:


    Allora qui sotto c'è una semplice classe Server che dovrebbe gestire più client ( cliché di noi newbie ) : Il fatto è che la comunicazione avviene bene sulla console (con System.out.println) anche con più cliente contemporaneamente, però " updateMessage " non aggiorna il componente. come invece avviene con un unico Client connesse e senza loop in " startConnection() ";
    Anche se conosco/uso poco JavaFX quel startConnection() mi pare molto "dubbio". Presumo che lo invochi a seguito di un "evento" di click su un pulsante. Ma allora sei nei UI thread e ... NON lo devi bloccare con un ciclo while teoricamente infinito.

    Poi comunque non mi pare molto "bello" che sia il task stesso a crearsi il "suo" ExecutorService.
  • Re: JavaFX attesa evento da un tasto

    quel startConnection() mi pare molto "dubbio". Presumo che lo invochi a seguito di un "evento" di click su un pulsante
    Si esatto.
    Poi comunque non mi pare molto "bello" che sia il task stesso a crearsi il "suo" ExecutorService.
    Si, l'ho modificato, ora uso un singolo ExecutorService nel while di startConnection(). Però continua a non modificare il componente tramite "updateMessage". Con un singolo Task Client e senza while per socket.accept() funziona. Devo capire perchè.


    Comunque grazie ugualmente Andbin
  • Re: JavaFX attesa evento da un tasto

    federaimondi ha scritto:


    Si, l'ho modificato, ora uso un singolo ExecutorService nel while di startConnection(). Però continua a non modificare il componente tramite "updateMessage". Con un singolo Task Client e senza while per socket.accept() funziona. Devo capire perchè.
    Il ciclo while con la accept lo devi fare in un thread/task a parte. E se vuoi fare un server "concorrente", per ciascuna connessione dovrai creare un ulteriore thread/task per gestire la connessione.
Devi accedere o registrarti per scrivere nel forum
8 risposte