Java : Customisation d’un JFileChooser (image preview, filtre, fileview)

Partager cet article

Temps estimé pour la lecture de cet article : 26 min

On continue la série sur les composants Swing avec le composant JFileChooser, il permet d’ouvrir une boite de dialogue pour sélectionner un fichier, comme les boutons parcourir que l’on trouve sur internet. Nous allons voir comment customiser ce composant.

On verra ainsi, comment modifier l’apparence des icônes affichées par le composant, la possibilité d’ajouter un filtre afin de limiter les fichiers recherchés, comment on peut permettre la multi-sélection et enfin comment il est possible d’ajouter une fonction de preview pour les images.

Allez un petit screenshot pour se donner du courage :

Java - FileChooser

On commencera par voir les pré-requis afin de pouvoir ajouter toutes ses options à notre composant et on finira par voir notre classe FileChooser qui va hériter de JFileChooser. Enfin on utilisera notre classe dans un exemple !

FileView : modifier l’apparence des icônes d’un JFileChooser

La classe JFileChooser, permet grâce à la fonction setFileView(), de changer l’apparence des icônes du composant. On va donc créer une classe CustomFileView qui va hériter de la classe FileView, on va pouvoir ainsi définir, les icônes qui nous intéressent.

package view;

import java.io.File;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileView;

public class CustomFileView extends FileView {
	private Icon fileIcon = new ImageIcon("data/file.png");
	private	Icon directoryIcon = new ImageIcon("data/folder.png");
	private	Icon imageIcon = new ImageIcon("data/photo.png");

	public String getName(File f) {
		return null;
	}

	public String getDescription(File f) {
		return null;
	}

	public String getTypeDescription(File f) {
		return null;
	}

	public Icon getIcon(File f) {
		Icon icon = null;

		if (isImage(f)) {
			icon = imageIcon;	
		} else if (f.isDirectory()) {
			icon = directoryIcon;	
		} else {
			icon = fileIcon;			
		}
		
		return icon;
	}

	private boolean isImage(File f) {
		String suffix = getSuffix(f);
		boolean isImage = false;

		if (suffix != null) {
			isImage = suffix.equals("gif") || suffix.equals("png") || suffix.equals("bmp")|| suffix.equals("jpg");
		}
		return isImage;
	}

	private String getSuffix(File file) {
		String filestr = file.getPath(), suffix = null;
		int i = filestr.lastIndexOf('.');

		if (i > 0 && i < filestr.length()) {
			suffix = filestr.substring(i + 1).toLowerCase();
		}
		return suffix;
	}
}

C’est la fonction getIcon(), qui va être utilisée afin de pouvoir remplacer l’icône voulue par la nôtre. On va alors utiliser la fonction isImage() afin de vérifier si le fichier sélectionné est une image. Pour ce faire on récupère l’extension du fichier grâce à la fonction getSuffixe().

Ajouter un filtre pour sélectionner un type de fichier précis

La classe FileNameExtensionFilter qui hérite de la classe FileFilter permet de définir un ensemble d’extensions. On peut par la suite préciser au JFileChooser soit de proposer ce filtre dans la liste de filtres déjà disponible, notamment grâce à la fonction addChoosableFileFilter() :

    String[] extensions = new String[] {"png","jpg","bmp","gif","jpeg"};
    FileNameExtensionFilter filter = new FileNameExtensionFilter("Image file", extensions);		                           
    addChoosableFileFilter(filter);

Soit de mettre ce type d’extension par défaut, ce qui permet par exemple pour un logiciel de manipulation d’images de retirer les fichiers inutiles (comme par exemple des fichiers txt…)

setFilter(filter);

Permettre la multi-sélection

Le JFileChooser permet facilement de réaliser de multiples sélections, une option est disponible, c’est la fonction setMultiSelectionEnabled() qui va nous y aider. Une fois l’option validée. On va pouvoir récupérer la liste des fichiers sélectionnés directement dans un tableau comme ceci :

JFileChooser fc = new FileChooser(filter);
int returnVal = fc.showSaveDialog(window);
if (returnVal == JFileChooser.APPROVE_OPTION) {
    File[] files = fc.getSelectedFiles(); 
    for (File file : files) {
	System.out.println(file.getAbsolutePath());
    }
}

Ajouter une fonction de preview

Il est facilement possible d’ajouter un nouveau composant graphique à un JFileChooser, pour ce faire on utilise la fonction setAccessory(), qui prend uniquement comme argument le composant à ajouter. Ici nous on appellera notre composant un PreviewPanel. Ce dernier contiendra seulement, un titre qu’on ajoute grâce à un JLabel et un JLabel personnalisé qu’on va appeler ImagePreviewer().

package view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Insets;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

public class PreviewPanel extends JPanel {
	private ImagePreviewer previewer;
	
	public PreviewPanel() {
		JLabel label = new JLabel("Image Previewer", SwingConstants.CENTER);
		previewer = new ImagePreviewer();

		setPreferredSize(new Dimension(150, 150));
		setBorder(BorderFactory.createEtchedBorder());

		setLayout(new BorderLayout());

		label.setBorder(BorderFactory.createEtchedBorder());
		add(label, BorderLayout.NORTH);
		add(previewer, BorderLayout.CENTER);
	}
	
	public ImagePreviewer getImagePreviewer() {
		return previewer;
	}

	class ImagePreviewer extends JLabel {
		public void configure(File f) {
			Dimension size = getSize();
			Insets insets = getInsets();
			ImageIcon icon = new ImageIcon(f.getPath());
			
			int width = size.width - insets.left - insets.right;
			int height = size.height - insets.top - insets.bottom;
			setIcon(new ImageIcon(icon.getImage().getScaledInstance(width,height,Image.SCALE_SMOOTH)));
		}
	}
}

La classe ImagePreviewer est une classe interne dont le but est de redimensionner l’image sélectionnée et l’adapter à notre panel de preview. Pour ce faire on utilise la fonction getScaledInstance().

FileChooser par l’exemple

Passons maintenant à notre classe principale qui hérite donc de JFileChooser, elle ajoute donc toutes les options qu’on a vues précédemment, la seule chose nouvelle c’est le PropertyChangeListener, c’est grâce à ce dernier que l’on va pouvoir afficher la nouvelle image sélectionnée dans le PreviewPanel.

package view;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;

public class FileChooser extends JFileChooser {
	private PreviewPanel previewPanel = new PreviewPanel();
	private FileFilter filter;
	
	public FileChooser(FileFilter filter) {
		super();
		setAccessory(previewPanel);
		addPropertyChangeListener(pcl);
	    setFileView(new CustomFileView());
	    
		this.filter = filter;
		addChoosableFileFilter(filter);
		setMultiSelectionEnabled(true);
	}
	
	PropertyChangeListener pcl = new PropertyChangeListener() {
		public void propertyChange(PropertyChangeEvent e) {
			if (e.getPropertyName().equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
				File f = (File) e.getNewValue();
				if(f != null) {
					if(f.isFile()) {
						String s = f.getPath(), suffix = null;
						int i = s.lastIndexOf('.');
						
						if (i > 0 && i < s.length() - 1) {
							suffix = s.substring(i + 1).toLowerCase();	
							
							if (suffix.equals("gif") || suffix.equals("png") || suffix.equals("jpg")) {
								previewPanel.getImagePreviewer().configure(f);						
							}
						}
					}
				}	

			}
		}
	};
	

}

On récupère donc le fichier sélectionné, on vérifie qu’il n’est pas null (un dossier par exemple), si c’est le cas, on récupère le chemin du fichier et on affiche la sélection grâce à la fonction configure() définit dans notre classe ImagePreviewer.

Et voilà, le gros du travail a été réalisé (enfin ^_^). Voici donc un exemple, Une fenêtre prend un JPanel et un bouton au clic sur le bouton on affiche notre FileChooser.

package launcher;

import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileNameExtensionFilter;

import view.BackgroundPanel;
import view.FileChooser;
import view.MyButton;

public class Main {
	public static void main(String[] args) {
		final JFrame window = new JFrame();
		BackgroundPanel back = new BackgroundPanel("data/back.jpg");
		MyButton button = new MyButton("Parcourir", "data/btn.png","data/btnh.png");
		
		window.setTitle("BackgroundPanel and Custom button !");
		window.setSize(800, 600);
		window.setLocationRelativeTo(null);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.add(back);
		back.setLayout(new GridBagLayout());
		window.setVisible(true);
		back.add(button);
		
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG file", new String[] { "png" });
				JFileChooser fc = new FileChooser(filter);
				int returnVal = fc.showSaveDialog(window);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					File[] files = fc.getSelectedFiles();
					for (File file : files) {
						System.out.println(file.getAbsolutePath());
					}
				}
			}
		});

	}
}

Voilou.

Remarque : les classes BackgroundPanel et MyButton ont été vues dans un article précédent.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.