IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

[API] Filtrage dynamique de liste


Sujet :

Java

  1. #1
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut [API] Filtrage dynamique de liste
    Salut,

    Suite à plusieurs posts que j'ai lu récemment concernant des demandes de filtrage de liste, et surtout parce que j'en ai moi-même besoin pour un projet, j'ai décidé de faire une petite API, qui se veut un plus générique que celle de JXList (d'ailleurs elle utilise la généricité). Et elle permet d'être utilisée directement dans une JList (ou autre).

    En fait il s'agit de la modélisation d'un filtrage, par forcément pour une JList, mais pour n'importe quoi, il suffit que ce n'importe quoi soit Filtrable<Type> (2 méthodes à définir : get(index) et getSize()).

    Il y a la notion de Filtrate<Type>, qui correspond au résultat du filtrage (comme en physique le résultat d'un filtration s'appelle filtrat, je l'ai appelé comme ceci ), et un filtrat est également filtrable (ainsi on peut refiltrer un filtrat, etc...). Il y a également la possibilité de définir un comparator sur un filtrat, pour que le résultat soit trié.

    Et donc il y a évidemment la notion de Filtre<Type>, et là il n'y a qu'une méthode à définir (si vous n'en utilisez pas un tout fait, comme StringFilter ou RegexFilter), il s'agit de boolean accept(D data) qui indique si la donnée doit être présente dans le filtrat ou non. On peut définir plusieurs filtres par filtrats...

    Il y a des méthodes permettant d'obtenir un ListModel ou ComboBoxListModel à partir d'un filtrable.

    Bon un petit exemple pour illustrer tout ça. Faisons une liste qui sera filtrée par un JTextField.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    		/*
    		 * Voici notre filtrable, ce sont nos données sources qui seront
    		 * filtrées, que nous ne modifirons pas ici. Pour pouvoir les modifier
    		 * de manière totalement libre, il vaut mieux utiliser un
    		 * AbstractFiltrable et coder les méthodes abstraites, et d'appeler les
    		 * fireXXX sur une modification (exactement comme vous le feriez avec un
    		 * AbstractListModel).
    		 */
    		Filtrable<String> filtrable = new DefaultFiltrable<String>("Java", "C", "C++", "Lisp", "CaML", "Fortran", "Lisaac", "x86", "HTML", "XML", "PHP", "JSP", "EJB", "Français", "çhîNöÏs");
     
    		/*
    		 * On récupère un filtrat (résultat du filtrage). Pour le moment il n'y
    		 * a pas de filtre (le texte du textfield est vide). On le déclare final
    		 * pour l'utiliser directement dans la classe anonyme de
    		 * DocumentListener (c'est juste pour l'exemple).
    		 */
    		final DefaultFiltrate<String> filtrate = new DefaultFiltrate<String>(filtrable);
    		/* On veut trier dans l'ordre alphabétique. */
    		filtrate.setSorter(String.CASE_INSENSITIVE_ORDER);
     
    		/* On veut utiliser notre filtrat comme modèle de la liste. */
    		ListModel listModel = FiltrableAdapters.toListModel(filtrate);
    		JList list = new JList(listModel);
     
    		/* On crée un textField, qui contiendra le texte de recherche. */
    		final JTextField textField = new JTextField();
    		/*
    		 * On écoute maintenant tous les évènements du textfield, ainsi à chaque
    		 * fois que l'utilisateur entre du texte, le contenu de la liste est mis
    		 * à jour.
    		 */
    		textField.getDocument().addDocumentListener(new DocumentListener() {
     
    			@Override
    			public void changedUpdate(DocumentEvent arg0) {
    				changed();
    			}
     
    			@Override
    			public void insertUpdate(DocumentEvent arg0) {
    				changed();
    			}
     
    			@Override
    			public void removeUpdate(DocumentEvent arg0) {
    				changed();
    			}
     
    			private void changed() {
    				/* On utilise un simple filtre de texte. */
    				Filter<String> filter = new StringFilter(textField.getText());
     
    				/* Filtre le contenu avec le nouveau filtre. */
    				filtrate.setFilter(filter);
    			}
     
    		});
     
    		JFrame frame = new JFrame("EModelFiltererDemo");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		frame.add(new JScrollPane(list));
    		frame.add(textField, BorderLayout.SOUTH);
    		frame.setBounds(100, 100, 150, 400);
    		frame.setVisible(true);
    Et enfin, un petit truc bien pratique, le SwingAsyncFiltrate<Type>, qui a 2 gros avantages.
    Pour comprendre son utilité, voyons d'abord ce que fait un filtrat "classique". Dans l'exemple ci-dessus, le filtrage est effectué chaque fois que du texte est entré dans le textfield. Supposons que le temps de filtrage soit long, par exemple il y a 1000 données dans la liste, et le Filter utilisé met 2 millisecondes par entrée. Cela fait une attente de 2 secondes à chaque lettre tapée dans le textfield! Et dans l'EDT, donc l'interface graphique se fige. Si vous tapez vite, ça va lagguer !

    Ce que permet SwingAsyncFiltrate<Type> :
    - filtrer dans un thread séparé, et notifier la fin du filtrage dans l'EDT (pratique pour afficher une info "veuillez patienter..." lors d'un filtrage, et le supprimer à la fin).
    - virer les demandes de filtrages inutiles dynamiquement. Reprenons notre exemple d'un filtrage qui dure 2 secondes, si en 2 secondes vous écrivez abcdefgh, il va chercher pour "a" (première lettre), mais au bout de 2 secondes, vous ne voulez pas qu'il recherche pour "ab", "abc", "abcd" ... puisque ce qui vous intéresse c'est le résultat pour "abcdefgh". Donc les filtrages inutiles ne seront pas effectués.

    Voici les liens:
    emodelfilter-api.zip
    emodelfilter-doc.zip
    emodelfilter-src.zip


    Donc voilà, j'ai programmé ça ce week-end, j'en suis très content (je l'utilise pour filtrer une liste de chaînes par 2 filtrats (et non 1 filtrat avec 2 filtres, car j'ai besoin du résultat intermédiaire également), tout d'abord par le groupe de favoris, et ensuite par le texte de recherche dans un textfield.

    Pour donner un exemple concret d'utilisation du Filter (on peut utiliser des filtres de base que l'on combine) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    /**
     * Filtre de chaînes.
     * 
     * @author <a href="mailto:rom1v@yahoo.fr">Romain Vimont</a> (rom1v)
     * @param <C>
     *            Type de chaînes.
     */
    public class ChannelFilter<C extends Channel> implements Filter<C> {
     
    	/**
             * Filtre de chaînes de caractères, utilisé pour filtrer le numéro et le nom
             * de la chaîne.
             */
    	private StringFilter filter;
     
    	/**
             * Crée un filtre de chaîne.
             * 
             * @param text
             *            Texte recherché.
             * @throws NullPointerException
             *             si le texte recherché est {@code null}.
             */
    	public ChannelFilter(String text) {
    		if (text == null) {
    			throw new NullPointerException();
    		}
    		filter = new StringFilter(text);
    	}
     
    	@Override
    	public boolean accept(C channel) {
    		/*
    		 * On accepte la chaîne si le filtre de chaîne de caractères accepte le
    		 * numéro de la chaîne ou s'il accepte le nom.
    		 */
    		return filter.accept(String.valueOf(channel.getNum())) || filter.accept(channel.getName());
    	}
     
    }
    Donc tout ça pour dire que moi ça me sert bien, si ça peut servir à d'autres...

    Si vous avez des suggestions, n'hésitez pas...

    @+

  2. #2
    Membre expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Points : 3 083
    Points
    3 083
    Par défaut
    Très bonne idée.
    Je m'étais déjà développé un genre de filtre pour une présentation dans une JList justement mais c'est vraiment light. Je vais essayer ton API dès que j'ai un peu de temps.

  3. #3
    Expert éminent sénior
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Ou si vous voulez un truc dans ce style encore plus généraliste, il existe les Glazed List (mais c'est largement plus gros...)

    http://publicobject.com/glazedlists/

  4. #4
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Si vous testez et que vous voyez un bug ou que vous avez une amélioration à proposer, n'hésitez pas

  5. #5
    Membre régulier
    Inscrit en
    Novembre 2005
    Messages
    110
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 110
    Points : 71
    Points
    71
    Par défaut
    Salut !
    J'ai ajouté ton filtre à mon pgm.. je le trouve bien pratique, il fonctionne vraiment bien!
    Toutefois, j'ai un truc bizarre avec ton jar et les class s'y trouvant. En fait, quand j'importe un package de ton api, dans une de mes classes, eclipse ne reconnaît pas du tout les objets et me les soulignes comme "unresolved symbols".

    J'ai du sans doute oublier de faire quelque chose, pour que Eclipse les trouve, mais quoi?

  6. #6
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Citation Envoyé par breezer911
    Salut !
    J'ai ajouté ton filtre à mon pgm.. je le trouve bien pratique, il fonctionne vraiment bien!
    Toutefois, j'ai un truc bizarre avec ton jar et les class s'y trouvant. En fait, quand j'importe un package de ton api, dans une de mes classes, eclipse ne reconnaît pas du tout les objets et me les soulignes comme "unresolved symbols".

    J'ai du sans doute oublier de faire quelque chose, pour que Eclipse les trouve, mais quoi?
    Clic droit sur ton projet, properties, java build path, onglet libraries, puis bouton add (external) jar pour ajouter ton jar...

    C'est quoi sinon un pgm...?

    Et une autre question tu as fait comment pour le faire marcher si eclipse ne le reconnaissait pas? Avec ant? à la main?

  7. #7
    Membre régulier
    Inscrit en
    Novembre 2005
    Messages
    110
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 110
    Points : 71
    Points
    71
    Par défaut
    Citation Envoyé par ®om
    Clic droit sur ton projet, properties, java build path, onglet libraries, puis bouton add (external) jar pour ajouter ton jar...
    Thx ca fonctionne mieux là d'un coup !

    Citation Envoyé par ®om
    C'est quoi sinon un pgm...?
    Sorry, c'est une abréviation pour programme... je sais le langage sms n'est pas autorisé, je ferai attention la prochaine fois

    Citation Envoyé par ®om
    Et une autre question tu as fait comment pour le faire marcher si eclipse ne le reconnaissait pas? Avec ant? à la main?
    Ba j'ai fait clik droit sur mon projet, import archive et là j'ai ajouté tes jars. Et puis cela fonctionne à la compilation... c'est juste Eclipse qui ne reconnait pas les jar.

Discussions similaires

  1. [AC-2010] Filtrage dynamique d'un contrôle liste
    Par sardaucar dans le forum IHM
    Réponses: 2
    Dernier message: 07/11/2013, 13h21
  2. Filtrage dynamique pour une liste?
    Par Lawsuit dans le forum IHM
    Réponses: 2
    Dernier message: 24/05/2011, 16h17
  3. Réponses: 9
    Dernier message: 07/08/2007, 15h36
  4. Pb filtrage dynamique formulaire
    Par STANDBOY dans le forum Access
    Réponses: 1
    Dernier message: 06/03/2006, 23h28
  5. Réponses: 5
    Dernier message: 09/08/2005, 18h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo