View Full Version : [Java] JFileChooser - selezionare il contenuto di una directory
Ho questa porzione di codice:
JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(false);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int retval = chooser.showOpenDialog(frame);
if (retval == JFileChooser.APPROVE_OPTION) {
try {
images = chooser.getSelectedFiles();
img = ImageIO.read(images[0]);
frame.getImagePanel().setImage(img);
frame.getContentPane().add(frame.getImagePanel(), BorderLayout.CENTER);
index = 0;
} catch (IOException ex) {
JOptionPane.showMessageDialog(frame, "Error opening image file!", "Error!", retval);
}
}
Mi servirebbe ottenere l'array di File[] non con una selezione multipla ma selezionando solo la directory che contiente questi file.
Con questo codice mi una "java.lang.ArrayIndexOutOfBoundsException".
banryu79
06-12-2010, 13:54
L'errore (semantico) sta qui:
...
images = chooser.getSelectedFiles();
...
quel metodo restiuisce l'istanza di tipo java.io.File selezionato dall'utente (in questo caso, dato che il selection mode del file chooser è stato settato a "DIRECTORIES_ONLY" e non è permessa la selezione multipla quel java.io.File corrisponderà alla cartella selezionata).
Quando poi, subito dopo fai:
...
img = ImageIO.read(images[0]);
...
è sbagliato perchè passi al metodo read l'abstract path name di una cartella, invece che di un file (una immagine).
Puoi risolvere il problema creandoti un metodo che, preso in input un java.io.File, se questo è una directory restituisca in output tutti i java.io.File che ti interessano (se vuoi tutti anche i file delle eventuali sottocartelle puoi implementare un metodo ricorsivo, oppure uno iterativo facendo ricorso ad uno stack).
@EDIT:
Svista mia, io parlavo del metodo getSelectedFile... tu invece invochi getSelectedFiles, e sbagli perchè getSelectedFiles, come dice la documentazione, può essere invocato solo se il file chooser è stato impostato a selezione multipla; evidentemente a selezione singola restituisce un array vuoto.
L'errore (semantico) sta qui:
...
images = chooser.getSelectedFiles();
...
quel metodo restiuisce l'istanza di tipo java.io.File selezionato dall'utente (in questo caso, dato che il selection mode del file chooser è stato settato a "DIRECTORIES_ONLY" e non è permessa la selezione multipla quel java.io.File corrisponderà alla cartella selezionata).
Quando poi, subito dopo fai:
...
img = ImageIO.read(images[0]);
...
è sbagliato perchè passi al metodo read l'abstract path name di una cartella, invece che di un file (una immagine).
Puoi risolvere il problema creandoti un metodo che, preso in input un java.io.File, se questo è una directory restituisca in output tutti i java.io.File che ti interessano (se vuoi tutti anche i file delle eventuali sottocartelle puoi implementare un metodo ricorsivo, oppure uno iterativo facendo ricorso ad uno stack).
Grazie per le dritte. Effettivamente l'eccezione che mi dà ha senso. ;)
Per ora ho risolto modificando leggermente il metodo di prima:
private void openDirActionPerformed() {
JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(false);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int retval = chooser.showOpenDialog(frame);
if (retval == JFileChooser.APPROVE_OPTION) {
try {
File imgDir = chooser.getSelectedFile();
images = imgDir.listFiles();
img = ImageIO.read(images[0]);
frame.getImagePanel().setImage(img);
frame.getContentPane().add(frame.getImagePanel(), BorderLayout.CENTER);
index = 0;
} catch (IOException ex) {
JOptionPane.showMessageDialog(frame, "Error opening image file!", "Error!", retval);
}
}
}
Però non mi è ben chiaro l'ordine degli elementi nell'array di File restituito dal metodo listFiles(). Nella documentazione pare che l'ordine degli elementi nell'array sia del tutto casuale. :D
banryu79
06-12-2010, 15:11
Sì, l'ordine di restituzione è non specificato.
Nota che come fai adesso non sei al riparo da due possibili tipi di errori/casi:
- la cartella selezionata dall'utente contiene (per qualsiasi ragione) altre cartelle;
- la cartella selezionata dall'utente contiene anche file che non sono immagini.
Puoi ovviare parzialmente "al volo" definendo un FilenameFilter da far usare durante la chiamata a listFiles(), così:
...
File imgDir = chooser.getSelectedFile();
images = imgDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return dir.isFile() && (name.endsWith(".jpg") || name.endsWith(".png") /*|| ecc...*/);
}
});
...
Sì, l'ordine di restituzione è non specificato.
Nota che come fai adesso non sei al riparo da due possibili tipi di errori/casi:
- la cartella selezionata dall'utente contiene (per qualsiasi ragione) altre cartelle;
- la cartella selezionata dall'utente contiene anche file che non sono immagini.
Puoi ovviare parzialmente "al volo" definendo un FilenameFilter da far usare durante la chiamata a listFiles(), così:
...
File imgDir = chooser.getSelectedFile();
images = imgDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return dir.isFile() && (name.endsWith(".jpg") || name.endsWith(".png") /*|| ecc...*/);
}
});
...
Io ho già una classe che estende FileFilter ma non so perchè eclipse mi segnala di rimuovere l'argomento se faccio
images = imgDir.listFiles(new MyFileFilter())
Comunque è un problema secondario perchè a me serve che le immagini dell'array images siano ordinate secondo la disposizione nella directory. Potrei ordinare successivamente l'array, avrebbe senso come soluzione?
banryu79
06-12-2010, 21:20
I
Comunque è un problema secondario perchè a me serve che le immagini dell'array images siano ordinate secondo la disposizione nella directory.
"Ordinate secondo la disposizione nella directory".
Definisci qual'è il criterio di ordinamento dei files in una directory, sei in grado?
Io no, anche perchè quello che vedi nella finestra della GUI è solo una "view" del contenuto della directory...
Adesso che me lo dici ho controllato, mi pare che i files/cartelle contenute in una directory siano ordinati (almeno di default nella view della GUI) secondo due criteri: primo vengono ordinati in ordine lessicografico crescente (considera che sono su un sistema Windows, ed è case insensitive) rispetto all'attributo "Tipo" (che è l'etichetta localizzata assegnata ad una precisa estensione, ad esempio per i file di tipo ".txt" l'etichetta che leggo è "Documento di testo" e viene inserito prima dei file di tipo ".bak" che hanno la laconica etichetta "File BAK") e dopo, a parità di "Tipo" in ordine lessicografico crescente rispetto al nome del file.
Potrei ordinare successivamente l'array, avrebbe senso come soluzione?
Sì, se hai questa neccessità.
Potresti crearti una classe che ha come membro un oggetto java.io.File, e che implementa l'interfaccia Comparable: in questo modo potresti sfruttare il fatto che il metodo java.util.Collections.sort() sfrutta l'implementazione del metodo compareTo dei singoli elementi di una collezione (che sono appunto dei Comparable) per ordinarli.
Oppure, senza definire una nuova classe (ma io procederei così, e all'internao della nuova classe implementerei compareTo nei termini dell'estensione del file, per simulare il primo criterio di ordinamento, quello che si basa sul tipo e poi del nome dei file: la classe si occuperebbe, dato un java.io.File in ingresso, di estrarre e gestire queste informazioni e i vari casi, ad esempio se il java.io.File in input non rappresenta un file ma una cartella) ma sempre sfruttando il comodo java.util.Collections.sort() (c'è anche la versione per gli array lisci) potresti implementare un tuo Comparator di java.io.File personalizzato.
"Ordinate secondo la disposizione nella directory".
Definisci qual'è il criterio di ordinamento dei files in una directory, sei in grado?
Io no, anche perchè quello che vedi nella finestra della GUI è solo una "view" del contenuto della directory...
Ordinamento di default, non l'avevo specificato, ovvero alfabetico (in kubuntu).
banryu79
06-12-2010, 23:07
Opterei per l'implementazione di un tuo Comparator da passare con la tua collezione di File a Collections.sort(), che fa il confronto tra due istanze di File in base al nome.
Per l'alfabetico ti basta usare la classe Collator in java.text, oppure potresti ovviare al problema del case trasformando tutti i nomi in uppercase o lowercase subito prima del confronto.
Opterei per l'implementazione di un tuo Comparator da passare con la tua collezione di File a Collections.sort(), che fa il confronto tra due istanze di File in base al nome.
Per l'alfabetico ti basta usare la classe Collator in java.text, oppure potresti ovviare al problema del case trasformando tutti i nomi in uppercase o lowercase subito prima del confronto.
Valutato che l'ordinamento che mi serve è di tipo lessicografico, faccio ordinare l'array di File semplicemente così:
private void openDirActionPerformed() {
JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(false);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int retval = chooser.showOpenDialog(frame);
if (retval == JFileChooser.APPROVE_OPTION) {
try {
File imgDir = chooser.getSelectedFile();
images = imgDir.listFiles();
Arrays.sort(images, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return o1.getName().compareTo(o2.getName());
}
});
img = ImageIO.read(images[0]);
frame.getImagePanel().setImage(img);
frame.getContentPane().add(frame.getImagePanel(), BorderLayout.CENTER);
index = 0;
} catch (IOException ex) {
JOptionPane.showMessageDialog(frame, "Error opening image file!", "Error!", retval);
}
}
}
Il controllo sull'estensione dei file lo voglio affidare ad una mia classe già creata che estende FileFilter ma il metodo listFiles(FileFilter filter) inspiegabilmente non mi accetta l'istanza di FileFilter come argomento (in documentazione c'è quel metodo! :confused: ).
Altro problema: dopo che la classe Arrays ha ordinato l'array images, l'elemento images[0] non contiene nessuna immagine. La prima immagine è contenuta in images[1] come se tutti gli elementi dell'array fossero splittati di una posizione a seguito dell'ordinamento.
banryu79
07-12-2010, 12:01
Il controllo sull'estensione dei file lo voglio affidare ad una mia classe già creata che estende FileFilter ma il metodo listFiles(FileFilter filter) inspiegabilmente non mi accetta l'istanza di FileFilter come argomento (in documentazione c'è quel metodo! :confused: ).
La tua classe non può estedere java.io.FileFilter perchè FileFilter è un''interfaccia :D
O hai una tua classe che la implementa oppure stai etendendo qualcos'altro che sia chiamata FileFilter... verifica.
Altro problema: dopo che la classe Arrays ha ordinato l'array images, l'elemento images[0] non contiene nessuna immagine. La prima immagine è contenuta in images[1] come se tutti gli elementi dell'array fossero splittati di una posizione a seguito dell'ordinamento.
'images' dovrebbe essere di tipo File[], giusto?
Prova a controllare cosa restituisce "imgDir.listFiles();" magari con una println o altro (debug passo-passo).
In questo momento non mi viene in mente nulla; il tuo comparator mi sembra ok.
La tua classe non può estedere java.io.FileFilter perchè FileFilter è un''interfaccia :D
O hai una tua classe che la implementa oppure stai etendendo qualcos'altro che sia chiamata FileFilter... verifica.
FilenameFilter è un'interfaccia, io estendo questa classe: http://download.oracle.com/javase/6/docs/api/
'images' dovrebbe essere di tipo File[], giusto?
Prova a controllare cosa restituisce "imgDir.listFiles();" magari con una println o altro (debug passo-passo).
In questo momento non mi viene in mente nulla; il tuo comparator mi sembra ok.
Aggiornamento: questo strano comportamento me lo fa solo con una directory composta da molte immagini tutte jpeg. Con le altre directory, contenenti anche png e gif, funziona alla perfezione. Mah.
banryu79
07-12-2010, 12:36
FilenameFilter è un'interfaccia, io estendo questa classe: http://download.oracle.com/javase/6/docs/api/
Sì, java.io.FilenameFilter è un'interfaccia e anche java.io.FileFilter lo è; non lo è javax.swing.filechooser.FileFilter :D
E i metodi nominati "listFiles" in java.io.File vogliono un java.io.FileFilter, non uno javax.swing.filechooser.FileFilter (questo filtro si usa con le API del file chooser) ;)
Sì, java.io.FilenameFilter è un'interfaccia e anche java.io.FileFilter lo è; non lo è javax.swing.filechooser.FileFilter :D
E i metodi nominati "listFiles" in java.io.File vogliono un java.io.FileFilter, non uno javax.swing.filechooser.FileFilter (questo filtro si usa con le API del file chooser) ;)
Sì, ovviamente ho una classe che estende javax.swing.filechooser.FileFilter. :D
Mi serviva come filtro per il JFileChooser e pensavo di riusarla con il metodo listFiles(). Adesso che mi hai fatto scoprire il perchè non funzionava mi è tutto più chiaro. ;)
Bene, ho risolto tutti i problemi in quest'ambito.
Ti dovrei erigere un monumento. :D :ave:
banryu79
07-12-2010, 13:17
Bene, ho risolto tutti i problemi in quest'ambito.
Ti dovrei erigere un monumento. :D :ave:
Se passi dalle parti di Padova fammi un fischio, una birra o un caffè e quattro chiacchere sono sempre ben accetti. :)
Se poi vuoi staccarmi un assegno non ho obiezioni :asd:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.