Newsgroup: it.comp.java
Titolo: Eventi da tastiera

Salve a tutti, premetto che nn sono un esperto programmatore java e
forse ve ne accorgerete dalla banalità delle mia domanda :-)
Dunque, supponiamo di aver creato un finestra in java e si voglia
renderla visibile quando un determianato tasto viene premuto e
lasciarla visibile durante tutto l'arco di tempo in cui il tasto viene
premuto, e renderla dinuvo invisibile quando questo tasto viene
rilasciato!!!
Ora nn conoscendo il codice, dalle API leggo che la classe KeyEvent
gestisce gli eventi che accadono quando si preme un tasto su un
componente....La mia domanda è questa, se all'inizio ovviamente il mio
componente (finestra) è invisibile l'applicazione nn eseguira mai la
parte del codice relativa al premere il tasto oppure si!!
Io cho provato ma al contrario, cioè all'inizio la finestra è
visibile, poi premendo un tasto "x" si rende invisibile e premendo il
tasto"y" la si rende di nuovo visibile. Ovviamente a me sparisce la
finestra ma poi nn si rivisualizza quando premo "y"....
Un'altra domanda e come fargli capire di renderla invisibile durante
tutto larco di tempo in cui si tiene premuto il tasto??Con un while e
un variabile booleana?
C'è qualche risposta alle mie due domande?
Grazie a tutti coloro che mi risponderanno
Francesco

Francesco ha scritto:

E' un problema di focus. Appena il tuo JFrame, o quello che è, diventa 
invisibile perde il focus, quindi tutti gli eventi della tastiera non 
"accadono su di lui".
Adesso bisogna vedere come è strutturata la tua applicazione: se hai due 
  finestra, puoi mettere il controlle degli eventi in quella sempre 
visibile e far comparire e sparire l'altra di conseguenza, ovviamente 
sempre stando attento alla gestione del focus.
Una prima idea, anche se un pò macchinosa potrebbe essere:
Frame A sempre visibile, Frame B a seconda:
Metto nel Frame A una action che stacca alla pressione di un tasto 
(occhio, esistono eventi diversi per pressione, click, rilascio ecc...) 
e mi fa comparire il Frame B.
Nel Frame B metto un action che lo fà sparire al rilascio del tasto.
Questa una prima idea. Altra idea potrebbe essere avviare un thread che 
si occupa di gestire questi eventi, ma è una soluzione che viene dal c e 
non saprei come implementarla. Ci dovrei pensare un pò.
Cmq le soluzioni di sono.
Delvy

Ho solo una finestra, io molto meccanicamente ho pensato di spostare la
location fuori dalla visibiltà dello schermo, ma come puoi ben intuire
è uno soluzione meccanica.
Per quanto riguarda la pressione del tasto nn so di preciso come
comportarmi...io nn so se si puo inserire un while che gestisce la
chiamata keypressed  ioe fino a quando ho tale evento una variabile
bool la setto a true e rendo frame visibile altrimenti quando rilascio
accade il contrario...
Comunque ho solo una finestra....gli eventi da tastiera mi pare di aver
capito che lavorano solo con i Component...se io faccio applicazione
normale senza Component nn posso definire eventi da tastier. Giusto?
Per il momento grazie dell aiuto

 Per il momento grazie dell aiuto
Purtroppo quello che vuoi fare (un listener "globale" a livello di sistema
operativo) non si può fare in java... o almeno, non in java puro. Dovresti
scrivere un driver che si aggancia a livello di kernel al driver della
tastiera, e attrezzarlo per rilevare la presenza della tua applicazione e
inviarle tutti gli eventi della tastiera... la vedo un po' duretta (senza
contare che perdi in portabilità)
-- 
Fermiamo Scientology prima che sia troppo tardi!!!
http://xenu.com-it.net
 - 
http://xenu.freewinds.cx/
 - 
http://www.xenu.net/
(per rispondere personalmente leva IlDitoDalCulo)

 Per il momento grazie dell aiuto
Purtroppo quello che vuoi fare (un listener "globale" a livello di sistema


 
Si esatto, alla fine il problema è che devi avere qualche cosa di attivo 
   con un Listener della tastiera, altrimenti non vedo una soluzione 
semplice.
Delvy

Quindi in sostanza è un bel problema!!!!

Ciao, scusami se ti scrivo in privato, ma sono abbastanza niubbo di Java ed
ho un problema per quanto riguarda la temporizzazione del disegno di un
JPanel; ho trovato per caso questo tuo post nel newsgroup it.comp.java e
credo che si tratti praticamente del mio problema!
Quindi ho pensato di scriverti in quanto mi sembri un utente molto esperto
di Java... Spero che potrai darmi un'indicazione perché non ho veramente più
idea di cosa fare!
Praticamente ho creato un piccolo programmino che svolge determinate
funzioni sulle serie di Fibonacci, graficando cose come il famoso problema
delle coppie di conigli e la spirale aurea, ma questo non ci interessa.
In ogni caso tali cose sono disegnate in un JPanel.
Quello che mi piacerebbe (ma purtroppo non riesco) fare é disegnare il
grafico non "tutto insieme" ma passo per passo, con passi distaccati di tot
millisecondi.
Avevo pensato al metodo Thread.sleep() ma francamente non so dove metterlo.
Infatti ho:
- un Listener (associato a un button) che avvia il disegno
- il Listener richiama un metodo start()
- start chiama il repaint() del JPanel
Ovvio che se aggiungo gli sleep direttamente nel paintComponent ho il solo
effetto di ritardare il disegno (che cmq viene sempre "tutto insieme"), ma
questo avviene anche se li metto nel metodo paint() o nel Listener, e da
quanto ho letto mi pare di aver capito che il problema é che il disegno non
si può "stampare" fin quando il controllo non torna al Listener che ha
invocato il tutto.
In uno schema del genere, come devo procedere per far funzionare il tutto?
Premetto che il programma non fa uso di Thread... é necessario che lo
faccia?
Ti ringrazio se mi risponderai... non so più dove sbattere la testa!

 Ti ringrazio se mi risponderai... non so più dove sbattere la testa!
Eh credo proprio di si:
1) Come ti ho detto prima, non ci deve essere nulla che impantani Swing
2) Hai bisogno di eseguire disegni in momenti diversi da quelli che Swing
decide per aggiornare la finestra
Comincio a darti qualche suggerimento, poi al massimo vediamo ti mettere
assieme qualche riga di codice se non ti è chiaro.
Prima di tutto, ti conviene creare un buffer di immagine in memoria (una
bitmap in pratica) su cui puoi disegnare ogni momento che vuoi *da qualsiasi
thread* (occhio alla sincronizzazione!!!). Secondo, modifica paintComponent
(ma anche solo paint potrebbe funzionare) in modo da "ridipingere" questa
bitmap sullo spazio disponibile, senza fare altro.
Per la bitmap in memoria, guarda la documentazione della classe
java.awt.image.BufferedImage
...e soprattutto il suo metodo getGraphics();
Ricordati di rilasciare le risorse quando hai finito di disegnare sulla
bitmap. Ah, ricordati di chiamare anche repaint() per "suggerire" a Swing
che c'è bisogno di un ridisegno.
Contrariamente a quanto molti pensano, repaint() non disegna proprio
nulla... serve solo per informare Swing che il contenuto visivo è cambiato
in qualche modo, e che deve essere ridisegnato tutto al più presto.
Un BufferedImage non è altro che un'implementazione dell'interfaccia Image,
puoi quindi "dipingerla" (drawImage) sopra il JComponent usando appunto
l'oggetto Graphics che ti viene passato quando Swing chiama il tuo paint().
Dimmi se ti basta :)
-- 
Fermiamo scientology prima che sia troppo tardi!!!


Innanzitutto scusami se ti ho scritto qui e se eravamo molto OT, ma avevo 
preparato la mail per mandartela privatamente, salvo poi scoprire che 
l'indirizzo da te posto era fasullo! In realtà bastava togliere 
IlDitoDalCulo ma l'ho letto solo adesso! :)
Ehi non pensare che mi piacesse tenermelo lì (in culo)! :)
Cmq ho riguardato x bene la risposta che avevi dato a Will ed ho risolto 
semplicemente come avevi suggerito a lui, ossia richiamando il metodo 
"temporizzato" attraverso un Thread; non ho utilizzato invokeLater in quanto 
non ce n'era bisogno ed ho utilizzato un booleano come controllo di 
sincronizzazione (in quanto i metodi "graficanti" il mio JPanel sono 2 e 
mentre uno é in funzione l'altro non é attivabile)...
Finalmente ora ho attenuto l'effetto voluto!
Ti ringrazio davvero tanto, mi 6 stato di grande aiuto!
Un'ultima cosa: non ho capito xké suggerisci a Will di dichiarare la 
variabile boolen start come "volatile"; dici che impedisce al compilatore di 
ottimizzarla, ma in che senso? Ed inoltre quando ho l'esigenza in un 
programma di dichiarare una variabile volatile? 

 programma di dichiarare una variabile volatile?
Ok, è un po' lungo ma vediamo di farla più "breve" possibile.
Prima di spiegarti cosa sia questa ottimizzazione, una piccola introduzione:
Solitamente la memoria di un computer viene indicata con il termine RAM
(Random Access Memory). In realtà esistono diversi tipi di memoria ad
accesso casuale: 
- la RAM classica, quei blocchi di chip che quantificano la memoria
utilizzabile in totale (cioè quella che hai installato sul pc). La loro
velocità dipende da come sono stati costruiti;
- la CACHE, chip di memoria molto più veloci della RAM classica, saldati
sulla scheda madre (Cache L3 e L2) o addirittura dentro il processore (Cache
L1). Possiedono una quantità di memoria molto più piccola, ma vengono usati
per identificare (e sostituire) locazioni di RAM lette e scritte più
frequentemente;
- i REGISTRI, blocchi di pochi byte immediatamente accessibili al processore
con istruzioni che vengono eseguite in tempi quantificabili in nanosecondi
(velocissime).
In ordine di velocità i tipi di memoria si classificano così:
- RAM (più lenta)
- CACHE L3 (ma non è sempre presente)
- CACHE L2
- CACHE L1
- REGISTRI (più veloci)
Una delle ottimizzazioni più comuni eseguite da interpreti e compilatori (e
Java non fa eccezione) è questa: la variabile più utilizzata viene fatta
corrispondere ad un registro del processore.
Il guaio di questa ottimizzazione è che, con l'elaborazione multithreading,
ad ogni thread corrisponde un'emulazione di processore, e quindi un "set di
registri" diverso. Eh si, ogni volta che il processore si dedica ad un altro
thread, c'è una procedura interna (scritta nel processore) che riversa il
contenuto dei registri in RAM (il più delle volte nella cache) e preleva il
set di registri del thread da "mettere in funzione" per la successiva "fetta
di tempo".
Senza avvertire il compilatore di nulla, la tua variabile booleana sarà la
migliore candidata ad essere messa in un registro (visto che sarà letta
migliaia di volte al secondo).
Questo però significa che avrai tante copie della tua variabile booleana
quanti saranno i thread in esecuzione, e la prima conseguenza è che se
qualche thread modifica il contenuto della variabile, gli altri thread
potrebbero ricevere il nuovo valore troppo tardi (fuori sincronia) o
addirittura non riceverlo mai... Tu dirai che è improbabile, io ti dico che
mi è già successo (in Java!)
Per ovviare a questo inconveniente, in Java è presente la parola chiave
"volatile", che garantisce che quella variabile non verrà MAI messa IN
NESSUN CASO in un registro di sistema, e che tutti i thread riceveranno
immediatamente un aggiornamento di quel valore appena un altro thread lo
cambia.
Meglio non rischiare, che ne dici? ;)


 programma di dichiarare una variabile volatile?
Ok, è un po' lungo ma vediamo di farla più "breve" possibile.





thread, c'è una procedura interna che riversa il contenuto dei registri in
RAM (il più delle volte nella cache) e preleva il set di registri del thread
da "mettere in funzione" per la successiva "fetta di tempo".
Senza avvertire il compilatore di nulla, la tua variabile booleana sarà la
migliore candidata ad essere messa in un registro (visto che sarà letta
migliaia di volte al secondo).
Questo però significa che avrai tante copie della tua variabile booleana
quanti saranno i thread in esecuzione, e la prima conseguenza è che se
qualche thread modifica il contenuto della variabile, gli altri thread
potrebbero ricevere il nuovo valore troppo tardi (fuori sincronia) o
addirittura non riceverlo mai... Tu dirai che è improbabile, io ti dico che
mi è già successo (in Java!)
Per ovviare a questo inconveniente, in Java è presente la parola chiave
"volatile", che garantisce che quella variabile non verrà MAI messa IN
NESSUN CASO in un registro di sistema, e che tutti i thread riceveranno
immediatamente un aggiornamento di quel valore appena un altro thread lo
cambia.
Meglio non rischiare, che ne dici? ;)
