Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1

    Ricerca con negazione in TextField

    ciao!

    in una TextField di JavaFX, ho impostato la ricerca dentro ad una TableView.
    una cosa del genere (vi posto solo questo pezzo di codice, ma se volete vi posto anche il resto):
    codice:
    txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
        filteredData.setPredicate(film -> {
            if (newValue == null || newValue.isEmpty()) {
                return true;
            }
            String lowerCaseFilter = newValue.toLowerCase();
            if (film.getTitle().toLowerCase().contains(lowerCaseFilter)) {
                return true;
            } else if (film.getNote().contains(lowerCaseFilter)) {
                return true;
            }
            return false;
        });
    });

    io vorrei fare in mododi fare la ricerca al contrario, nel senso di escludere dalla ricerca le parole che stanno dopo il punto esclamativo (non so se mi sono spiegato).
    è possibile?
    qualche dritta??

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da fermat Visualizza il messaggio
    nel senso di escludere dalla ricerca le parole che stanno dopo il punto esclamativo
    Di quale punto esclamativo stai parlando? Cioè hai un titolo "Ciao! Paperino" e se cerchi Paperino non vuoi matchare quel titolo perché la parola si trova dopo il '!' ?
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  3. #3
    ciao andbin!

    si in pratica vorrei fare che se cerco !paperino mi dovrebbe tirar fuori tutti i record che non hanno paperino.

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da fermat Visualizza il messaggio
    si in pratica vorrei fare che se cerco !paperino mi dovrebbe tirar fuori tutti i record che non hanno paperino.
    Ok scusa .. ho capito. Il '!' come negazione che scrive l'utente per ignorare una parola. Ma vuoi farlo per ciascuna parola che l'utente inserisce nel textfield? Per esempio l'utente inserisce:

    !paperino topolino !pippo

    Quindi cerchi tutti i titoli/note che: hanno topolino E non hanno paperino E non hanno pippo
    E la ricerca nel titolo/note deve restare con il contains() oppure pensi di farla in modo "stretto" parola per parola (per intenderci: se l'utente scrive !pippo, un titolo con dentro pippone vuoi scartarlo oppure no?)
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  5. #5
    allora, do qualche dettaglio in più.
    la TableView è riempita con dati da libreria (ogni voce una colonna):
    - titolo
    - autore
    - editore
    - prezzo
    - isbn
    - note

    al momento la ricerca l'ho impostata su titolo, autore (aggiunto adesso, messo codice sotto) e note.
    magari quegli if poi li sistemo.
    un esempio di ricerca "al contrario" del tipo: trova tutti i libri che non sono scritti da stephen king.
    quindi nella TextField mi verrebbe da scrivere !king oppure !stephen.

    considerando che i risultati si vedono in tempo reale nella TableView, nella maggior parte dei casi non finisco neanche di scrivere tutta la ricerca.


    codice:
    txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
        filteredData.setPredicate(film -> {
            if (newValue == null || newValue.isEmpty()) {
                return true;
            }
            String lowerCaseFilter = newValue.toLowerCase();
            if (film.getTitle().toLowerCase().contains(lowerCaseFilter)) {
                return true;
            } else if (film.getAuthor().toLowerCase().contains(lowerCaseFilter)) {
                return true;
            } else if (film.getNote().contains(lowerCaseFilter)) {
                return true;
            }
            return false;
        });
    });

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Io cercherei di risolvere la questione in maniera object-oriented, separando bene i concetti. Ci sono infatti 2 concetti che sarebbero da tenere separati: il concetto del pattern da gestire (es. "!stephen !king") e il concetto del criterio di match all'interno di un oggetto (es. Film).

    Io una ideuzza ce l'avrei, se vuoi te la espongo .... c'è ben più codice da scrivere ma sarebbe riutilizzabile e ridurrebbe quel tuo listener a 2~3 righe.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  7. #7
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Io cercherei di risolvere la questione in maniera object-oriented, separando bene i concetti. Ci sono infatti 2 concetti che sarebbero da tenere separati: il concetto del pattern da gestire (es. "!stephen !king") e il concetto del criterio di match all'interno di un oggetto (es. Film).

    Io una ideuzza ce l'avrei, se vuoi te la espongo .... c'è ben più codice da scrivere ma sarebbe riutilizzabile e ridurrebbe quel tuo listener a 2~3 righe.
    bhe si grazie, quando hai tempo se ti va esponi!
    almeno imparo qualcosa di nuovo!

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da fermat Visualizza il messaggio
    bhe si grazie, quando hai tempo se ti va esponi!
    almeno imparo qualcosa di nuovo!
    Innanzitutto puoi fare una semplice interfaccia:

    codice:
    public interface TextMatcher {
        boolean matches(String text);
    }

    Poi in modo specifico per Film (ma lo potrai fare similarmente per qualunque altro oggetto) fai una classe di implementazione di TextMatcher:

    codice:
    public class FilmTextMatcher implements TextMatcher {
        private String titolo;
        private String author;
        private String note;
    
        public FilmTextMatcher(Film film) {
            titolo = film.getTitle().toLowerCase();
            author = film.getAuthor().toLowerCase();
            note = film.getNote().toLowerCase();
        }
    
        @Override
        public boolean matches(String text) {
            text = text.toLowerCase();
            return titolo.contains(text) || author.contains(text) || note.contains(text);
        }
    }

    Nota che in FilmTextMatcher NON c'è alcuna logica del "negativo". Un FilmTextMatcher fa solo una cosa: data una stringa la cerca all'interno dell'oggetto Film e restituisce se la trova o no. Per farlo deve stabilire: a) "dove" cercarla (in quali campi) e b) "come" cercarla (con contains() piuttosto che startWith() ecc...). Solo FilmTextMatcher "sa" come fare queste due cose (che sono specifiche di Film, ovviamente). E non fa altro.

    Poi fai una classe SearchPattern che rappresenta il pattern inserito dall'utente e che ha la capacità di "matchare" con un TextMatcher.

    codice:
    public class SearchPattern {
        private final Item[] items;
    
        public SearchPattern(String text) {
            String[] tokens = text.split("\\s+");
    
            items = new Item[tokens.length];
    
            for (int i = 0; i < items.length; i++) {
                items[i] = new Item(tokens[i]);
            }
        }
    
        public boolean matches(TextMatcher textMatcher) {
            boolean allMatch = true;
    
            for (int i = 0; allMatch && i < items.length; i++) {
                Item item = items[i];
                boolean match = textMatcher.matches(item.getText());
    
                if (item.isNegative()) {
                    allMatch &= !match;
                } else {
                    allMatch &= match;
                }
            }
    
            return allMatch;
        }
    
        private static class Item {
            final boolean negative;
            final String text;
    
            public Item(String text) {
                if (text.startsWith("!")) {
                    this.text = text.substring(1);
                    negative = true;
                } else {
                    this.text = text;
                    negative = false;
                }
            }
    
            public boolean isNegative() {
                return negative;
            }
    
            public String getText() {
                return text;
            }
        }
    }

    Nota come SearchPattern analizza il pattern in input (es. "!stephen !king") e si "compila" una lista di Item che rappresentano ciascun pezzo del pattern, con o senza la negazione.
    Quindi il matches semplicemente "prova" ciascuno di questi pezzi contro il TextMatcher. Ed è qui che viene usato il concetto di "negato". Se nel pattern c'è !stephen e stephen lo TROVO, allora per la negazione non è valido e allMatch diventa false.


    A quel punto il tuo listener diventa:

    codice:
    txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
        SearchPattern searchPattern = new SearchPattern(newValue);
        filteredData.setPredicate(film -> searchPattern.matches(new FilmTextMatcher(film)));
    });

    che puoi ancora abbreviare, se vuoi.

    Non è gestito il caso in cui newValue possa essere null ma in teoria non dovrebbe mai esserlo (non ho bene idea adesso sul textfield di JavaFX, dovrei documentarmi).
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  9. #9
    ciao andbin!

    intanto grazie mille, funziona alla perfezione!!
    me lo sono studiato tutto, ed ho capito il concetto che gli sta dietro.
    avrei solo un dubbio nel metodo matches della classe SearchPattern.

    nello specifico:
    codice:
    if (item.isNegative()) {
        allMatch &= !match;
    } else {
        allMatch &= match;
    }

    quel &=.
    mi sono letto della documentazione in giro, ma non riesco ad applicare il concetto a questo caso.


    per quanto riguarda il null, se intendi la casella vuota, semplicemente non c'è filtro.
    quindi nella TableView si vede tutto (quindi esattamente come vorrei che fosse).

  10. #10
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da fermat Visualizza il messaggio
    quel &=.
    mi sono letto della documentazione in giro, ma non riesco ad applicare il concetto a questo caso.
    L'operatore & applicato ai boolean dà la AND "logica" (a & b dà true se entrambi i boolean sono true). &= è semplicemente la AND composta con l'operatore di assegnamento.

    Quote Originariamente inviata da fermat Visualizza il messaggio
    per quanto riguarda il null, se intendi la casella vuota, semplicemente non c'è filtro.
    quindi nella TableView si vede tutto (quindi esattamente come vorrei che fosse).
    Nel tuo codice avevi messo

    if (newValue == null || newValue.isEmpty()) {

    Nel mio

    codice:
    public SearchPattern(String text) {
        String[] tokens = text.split("\\s+");

    Non ho testato per il null. Se text è vuoto (""), split dà un array di lunghezza 0 (che non causa problemi). Se text fosse null, chiaramente lo split non è invocabile, causando NullPointerException.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.