View Full Version : [Java] Problemi con Drag&Drop. Swing
kevinpirola
15-10-2010, 18:39
Ciao a tutti, sto compilando in java una "galleria fotografica" che visualizza le foto presenti in una cartella.
Tralasciando i vari casini per impostare la grafica io praticamente leggo tutte le immagini da una cartella e ne metto il nome in un array.
Da quell'array con un semplice ciclo for mi creo le anteprime prima aprendo l'immagine da file, poi ridimensionandola e infine creando l'Icon da mettere in una JLabel.
Ora, se faccio in modo che al posto di essere in una JLabel le immagini siano dei bottoni posso facilmente passarmi il dato "numero" dell'immagine per andare a leggere nell'array il percorso di tale immagine e poi scriverla sulla destra dello schermo nella sezione anteprima (più grande)
se invece voglio fare il drag&drop di JLabel (quindi non usando i JButton), ossia prendere la thumb e spostarla nella parte di destra per aprire l'immagine grande da quella parte, mi trovo in grosse difficoltà poichè non so come passarmi dati e se passo la icon delle thumb quando la vado a scrivere nella JLabel è ovviamente della misura a cui l'avevo ridimensionata.
Se vado (con non pochi casini tra parentesi) a ricrearmi una Image per ridimensionarla ovviamente viene tutta pixellosa.
Come potrei fare? sono in crisi perchè sono ad un punto morto.... la icon che passo non ha più nessun riferimento con l'immagine di partenza e quindi nemmeno con equals posso più far niente... non so che fare...
ecco il codice che ho scritto fino ad adesso.
IL CODICE E' UN PROGETTO NON DISTRIBUIBILE PRIMA DEL 20 OTTOBRE.
in caso di necessità email me.
qualcuno ha qualche idea su come implementare un drag&drop che mi sia funzionale?
tutto ciò che è commentato con nome boton[i] è per farlo funzionare con il pulsante
banryu79
15-10-2010, 19:45
Prima una precisazione: non ho guardato codice che hai postato.
Ma per rispondere non è strettamente neccessario, al momento, dato che il problema da risolvere è concettuale.
...
Tralasciando i vari casini per impostare la grafica io praticamente leggo tutte le immagini da una cartella e ne metto il nome in un array.
Da quell'array con un semplice ciclo for mi creo le anteprime prima aprendo l'immagine da file, poi ridimensionandola e infine creando l'Icon da mettere in una JLabel.
...
Hai un array con i nomi dei file delle immagini.
Bene. Il nome del file dell'immagine ti fornisce l'aggancio neccessario per andare a leggere l'immagine originale ogni volta che ti è neccessario farlo.
Hai la thumb di una immagine caricata in memoria in una JLabel.
Purtroppo così la singola JLabel istanziata non conserva nessun riferimento con l'immagine originale.
Basterebbe che conoscesse l'indice nell'array dei nomi dei file...
Puoi farlo in tanti modi, alcune idee:
-> Ti crei una classe che contiene due membri di istanza: la tua JLabel e un intero (indice nell'array dei nomi dei file).
-> Sostituisci l'array dei nomi dei file con una mappa (java.util.Map) che come chiave ha ha la Label con l'immagine thumb creata e come valore ha un Integer (indice nell'array dei nomi dei file).
Questo per iniziare con alcune idee.
Poi si possono fare certe valutazioni relativamente al fatto di tenere o meno in memoria un'immagine "originale" una volta letta da disco in modo da non doverla rileggere (ma questo richiede di usare maggiore memoria).
Si possono tenerle tutte, oppure si può limitare la cosa.
Un'idea in questo senso è creare una classe, diciamo ImageLibrary che al suo interno gestisce una mappa che chiamiamo con spreco di fantasia "imageMap".
Le chiavi di imageMap sono i nomi dei file delle immagini.
I valori di imageMap sono istanze di un'altra classe che creiamo noi, che chiamiamo ImagePair, dotata di due membri di tipo Image (uno per l'immagine originale caricata in memoria, l'altro per la thumbnail).
Quando nell'applicazione abbiamo bisogno di un'immagine, ad esempio una thumbnail, la chiediamo a ImageLibrary dicendogli getThumbnailFor e indicandogli il nome del file dell'immagine che vogliamo.
Se invece vogliamo l'immagine originale diremo a ImageLibrary getImageFor sempre indicandogli il nome dell'immagine desiderata.
All'invocazione di tali metodi in ImageLibrary verrà recuperata da imageMap la ImagePair associata tramite la chiave data (il nome del file).
Dalla ImagePair verrà quindi recuperata o la thumbnail o l'immagine intera. Se una di queste due risorse non è presente (retituzione di un riferimento nullo, ad esempio) verrà prima caricata dal file, poi memorizzata in imageMap e infine restituita.
1) se viene richiesta un'immagine "originale" non presente in imageMap le operazioni da fare sono:
- leggere da file quell'immagine
- memorizzare l'immagine nell'istanza di ImagePair in imageMap
2) se viene richiesta un'immagine "thumb" non presente in imageMap le operazioni da fare sono:
- ottenere da imageMap la corrispettiva immagine "originale" (che se non presente implica la procedura al punto 1)
- generare la versione "thumb" dell'immagine
- memorizzare la thumb nell'istanza di ImagePair in imageMap
In questo modo leggi una sola volta le immagini e le mantieni in memoria... però questo potrebbe essere troppo costoso, e dipende dal numero e dalla grandezza dei file delle immagini.
Ci sono dei rimedi.
Uno è quello di decidere di tenere in memoria al massimo N immagini (con N grande a piacere). In questo caso basta, ad ogni caricamento di una nuova immagine non presente in imageMap verificare il valore di una variabile che usiamo come contatore in ImageLibrary: se è minore di N allora possiamo caricare un'altra immagine e incrementare il contatore, altrimenti dobbiamo "cestinare" un'immagine già caricata e caricare quella appena richiesta.
Questo solo per darti qualche spunto di riflessione.
kevinpirola
15-10-2010, 20:08
Grazie mille ottime idee, ora mi metto sotto per implementarle, una cosa però non ho capito... come faccio a passare dati (diversi da icon) tramite il drag&drop? nel senso io passo l'immagine che però ovviamente non mi serve.. dovrei passare una istanza della nuova classe con la JLabel e la variabile che mi tiene conto dell'indice dell'array delle immagini oppure almeno un testo...
ho riletto un po' di volte quello che hai scritto ma non menzioni il momento cruciale passare i dati con il drag&drop...
(ti ringrazio già comunque per l'ottima spiegazione e il tempo che mi hai dedicato)
banryu79
15-10-2010, 20:59
ho riletto un po' di volte quello che hai scritto ma non menzioni il momento cruciale passare i dati con il drag&drop...
Non l'ho menzionato perchè sul fronte drag'n'drop in Swing non ne so un ceppa :D
Comunque se non ho capito male quello che ti serve, per il drag'n'drop, forse potresti cavartela con un piccolo wrapper: definisci una classe che estende JLabel (il tipo di componente che attualmente usi per implementare la thumb come oggetto grafico nella GUI) e che in più è dotata di un membro int per associare la thumb con l'indice nell'array dei nomi dei file delle immagini.
A quel punto se sei in grado di fare un uso opportuno del drag'n'drop in Swing dovresti poter passare questo oggetto dal tuo pannello a dx al''area di visualizzazione delle foto originali a snx dove potrai leggere da disco l'immagine corretta sfruttando l'indice associato.
kevinpirola
15-10-2010, 21:07
è esattamente quello che sto provando a fare in questo momento :D
grazie mille
se qualcuno sa bene come funziona il D&D io sono ancora bisognoso :D
bluled85
15-10-2010, 21:11
Buona Idea!
I tutor di Ing. del SW.
banryu79
15-10-2010, 21:16
se qualcuno sa bene come funziona il D&D io sono ancora bisognoso :D
Io un nome in mente ce l'avrei...
Finchè non si fa vivo qualcuno che ne sa, ti segnalo una lettura che forse ti è utile, circa le questioni del drag'ndrop in Swing.
Link -> http://www.hwupgrade.it/forum/showthread.php?t=1390640
Vedi soprattutto il post dell'utente PGI-Bis.
E qui trovi la lezione ufficiale sul Drag'n'Drop dei Java Tutorials -> http://download.oracle.com/javase/tutorial/uiswing/dnd/index.html
kevinpirola
15-10-2010, 21:28
Buona Idea!
I tutor di Ing. del SW.
:) lol buona idea chiedere qui oppure buona idea quello che ho fatto fino ad ora? :)
bluled85
15-10-2010, 21:48
:) lol buona idea chiedere qui oppure buona idea quello che ho fatto fino ad ora? :)
Buona idea chiedere qui, senza dubbio... :)
Inoltre secondo il TL di GUI, anche il lavoro svolto fino ad ora non sembra male(ad una prima occhiata).
Per chi si sta chidendo che significhi questa conversazione:
il lavoro svolto da "kevinpirola" è un homework assegnato per l'ammissione al corso di Ingegneria del Software (che è stato preceduto da un test attitudinale ed un colloquio personale). L'unico vincolo imposto era non consultarsi con gli altri partecipanti (e non avrebbe senso essendo il numero di posti limitati), quindi chiedere informazioni in un forum risulta perfettamente lecito.
kevinpirola
15-10-2010, 21:57
Buona idea chiedere qui, senza dubbio...
Inoltre secondo il TL di GUI, anche il lavoro svolto fino ad ora non sembra male(ad una prima occhiata).
Per chi si sta chidendo che significhi questa conversazione:
il lavoro svolto da "kevinpirola" è un homework assegnato per l'ammissione al corso di Ingegneria del Software (che è stato preceduto da un test attitudinale ed un colloquio personale). L'unico vincolo imposto era non consultarsi con gli altri partecipanti (e non avrebbe senso essendo il numero di posti limitati), quindi chiedere informazioni in un forum risulta perfettamente lecito.
bene bene.. ho ancora ben 62 ore di lavoro riuscirò a fare sto cavolo di drag&drop..
Ma fare il tutto graficamente più bello e con funzioni in più è meglio oppure "it's a waste of time" ?
bluled85
15-10-2010, 22:15
Purtroppo non posso dirle altro, in primo luogo perchè non sarò io a correggere il suo elaborato, ma il responsabile di GUI, in secondo luogo non sarebbe corretto nei confronti degli altri studenti che non hanno ricevuto alcuna informazione aggiuntiva. :fiufiu:
kevinpirola
16-10-2010, 01:34
giusto giusto!
io intanto continuo la mia campagna votiva a un po' di Santi..
EDIT CODICE NON COMPLETO. IL PROGETTO NON E' RIDISTRIBUIBILE PRIMA DEL 20 OTTOBRE.
in caso di necessità email me.
//classe dragdrop
MouseMotionListener mouseML = new MouseMotionAdapter()
{
public void mouseMoved(MouseEvent me)
{
t = Integer.parseInt(foto.getText());
Image z=java.awt.Toolkit.getDefaultToolkit().getImage(dati[t]);
z=z.getScaledInstance(370,370,Image.SCALE_DEFAULT);
Icon img = new ImageIcon(z);
foto.setIcon(img);
}
public void mouseDragged(MouseEvent me)
{
t = Integer.parseInt(foto.getText());
Image z=java.awt.Toolkit.getDefaultToolkit().getImage(dati[t]);
z=z.getScaledInstance(370,370,Image.SCALE_DEFAULT);
Icon img = new ImageIcon(z);
foto.setIcon(img);
}
};
MouseListener mouseListener = new MouseAdapter ()
{
public void mousePressed (MouseEvent me)
{
JComponent comp = (JComponent) me.getSource ();
TransferHandler handler = comp.getTransferHandler ();
handler.exportAsDrag (comp, me, TransferHandler.COPY);
t = Integer.parseInt(foto.getText());
System.out.println(t);
Image z=java.awt.Toolkit.getDefaultToolkit().getImage(dati[t]);
z=z.getScaledInstance(370,370,Image.SCALE_DEFAULT);
Icon img = new ImageIcon(z);
foto.setIcon(img);
}
};
foto.addMouseMotionListener (mouseML);
//THUMBNAILS
pcolo.setLayout(new GridLayout(5,1));
int j = 0;
i = 0;
priga[j] = new JPanel();
priga[j].setLayout(new FlowLayout(FlowLayout.LEADING));
for(i =0; i < c; i++){
if (i % 5 == 0 && i!=0){
j++;
priga[j] = new JPanel();
priga[j].setLayout(new FlowLayout(FlowLayout.LEADING));
}
Image x=java.awt.Toolkit.getDefaultToolkit().getImage(dati[i]);
x=x.getScaledInstance(50,50,Image.SCALE_DEFAULT);
Icon icona = new ImageIcon(x);
thumb[i]= new JLabel(Integer.toString(i),icona,SwingConstants.CENTER);
thumb[i].setTransferHandler (new TransferHandler ("text"));
thumb[i].addMouseListener (mouseListener);
thumb[i].setVerticalTextPosition(SwingConstants.NORTH);
thumb[i].setHorizontalTextPosition(SwingConstants.CENTER);
priga[j].add(thumb[i]);
}
for(int e = 0; e<=j;e++){
pcolo.add(priga[e]);
}
/**
* Inserisce in un array le foto.
*/
public static void getDati(){
}
}
ecco il codice completo EDIT: RESTA SOLO LA PARTE DEGLI EVENTI DEL MOUSE. Ora si riesce a drag'n'droppare le varie thumb ho solo una domanda, c'è un modo per ciclare un evento che avvenga ogni tot?
mi spiego. L'immagine grande varia al variare di una variabile che viene modificata ogni volta che ci si sposta sopra una thumb. Ovviamente il valore di questa var è l'indice corrispondente alla nuova immagine nell'array delle immagini estratto all'inizio del file.
Ora come ora funziona così.
Start drag.
Release (Si aggiorna il valore del testo della label grande)
mousemove (leggo il valore del testo, lo imposto nella variabile e cambio l'immagine grande)
ovviamente il tutto funziona il solo problema è che se io droppo la thumb e tengo il mouse fermo non avviene l'evento mouseMoved e quindi non viene chiamato il metodo di aggiornamento.
Se metto il metodo di aggiornamento sul mouseReleased non funziona.
Allora dico io, c'è un modo per far si che questa variabile venga controllata ogni tot millisecondi e a seconda dei suoi cambiamenti aggiornata l'immagine grande?
(Paradossalmente in flash ActionScript metterei una cosa del tipo:
movieClip vuoto, onClipEvent(enterFrame) [cioè ogni volta che parte il filmato quindi a seconda del framerate tot volte al secondo]
e dentro a questo ci metto la funzione che va ripetuta...
io ho provato a fare una cosa tipo
public static void ciclo(){
//AZIONE
//AZIONE
try {
Thread.sleep(80);
} catch(InterruptedException ex) {
//eccezione
}
ciclo();
ma come potete immaginare si impianta tutto...
ho provato allora con un ciclo for. pensando che associo ciclo ad un evento, faccio un for tot volte (imposto sleep a 500ms faccio 30 cicli di for, passano 15 secondi in cui la funzione è attiva ogni mezzo secondo)
invece appena viene richiamata ciclo(); il tutto si impianta per 15 secondi e non posso fare nulla.
Idee?
banryu79
16-10-2010, 13:08
Premessa: non ho letto tutto il codice (ma va? :))
...
ecco il codice completo. Ora si riesce a drag'n'droppare le varie thumb ho solo una domanda, c'è un modo per ciclare un evento che avvenga ogni tot?
...
prova a dare un occhio alla classe javax.swing.Timer (vedi i javadoc).
...
ovviamente il tutto funziona il solo problema è che se io droppo la thumb e tengo il mouse fermo non avviene l'evento mouseMoved e quindi non viene chiamato il metodo di aggiornamento.
Se metto il metodo di aggiornamento sul mouseReleased non funziona.
...
Domande:
1) perchè il "metodo di aggiornamento" non lo puoi lanciare al termine del gesto di release?
2) In mouse released "non funziona": mi suona strano... controllerei di usare bene i listener... ma bisognerebbe vedere il codice scritto per capire bene.
In genere per aggiornare il rendering di un componente in Swing è sufficiente chiamare il metodo repaint(); per certi componenti e in talune circostanze però non è sufficiente e bisogna invocare anche altri metodi (revalidate).
kevinpirola
16-10-2010, 13:39
nel release non funziona perchè ho notato (mettendo qualche System.out in giro) che praticamente legge come release se tu clicchi e rilasci semplicemente...
se invece clicchi, cominci il drag quando rilasci non è più un "release" bensì un qualcosa di diverso che può essere interpretato come un "drop"..
questa sera proverò a dare un occhio alla swing.timer
mal che vada se non riesco a farlo funzionare il drag e drop per il momento va anche se non è perfetto...
kevinpirola
16-10-2010, 13:45
Ora ho un problema di eccezione se la cartella è vuota ma non riesco a catcharlo... :(
banryu79
16-10-2010, 13:46
nel release non funziona perchè ho notato (mettendo qualche System.out in giro) che praticamente legge come release se tu clicchi e rilasci semplicemente...
se invece clicchi, cominci il drag quando rilasci non è più un "release" bensì un qualcosa di diverso che può essere interpretato come un "drop"..
Ora no ricordo, ma prova a vedere se lo considera un "mouseClicked" invece...
banryu79
16-10-2010, 13:47
Ora ho un problema di eccezione se la cartella è vuota ma non riesco a catcharlo... :(
1 a 10 che è una NullPointerException...
kevinpirola
16-10-2010, 13:51
1 a 10 che è una NullPointerException...
eh beh certo... però non so dove sbattere la testa, ho messo try catch dappertutto ma non trovo nessun riferimento all'errore....
p.s. per ovvi motivi ho modificato il codice, se ti serve l'integrale te lo mando via pm.. basta che mi mandi un pm in risposta
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.