# JList filtern



## vanny (23. Okt 2011)

Hi,

ich arbeite an einem Programm, wie´s jeder kennt, DB mit Kunden, Rechnungen, Bestellungen usw.
Nun möchte ich nicht zig Formulare für ""suche Kunde, Rechnung..." benutzen, sondern ein Eingabefeld für den Suchbegriff und fertig.
Diese Suchergebnisse landen dann alle in einer Liste, die in einer JList angezeigt werden.
Nun habe ich mir mittels JRadioButtons eine Schaltfläche erstellt, in der der User dann auswählen kann, welche Ergebnisse er in der JList sehen will. Ein banaler Filter halt.

Soweit so gut, es funktioniert auch alles.

Meine frage ist, ob man diese Filterfunktion irgendwie direkt an die JList/ListCellRenderer anknüpfen kann.
Zur Zeit lösche ich bei jedem FilterEvent die daten aus dem ListModel und füge sie dann gefiltert wieder hinzu.
Wäre glaube ich eleganter, wenn das Model die Daten behalten könnte und wirklich nur die Anzeige gefiltert wird.

Vielleicht hat ja jemand schon mal einen ähnlichen Ansatz verfolgt und kann mir nen Tipp geben.

Danke und Gruß Vanny


----------



## Gast2 (23. Okt 2011)

Bei ner JList hast du imho keine Möglichkeit die Daten zu filtern. Anders ist das bei ner JTable, die kann von Haus aus Daten sortieren und auch filtern (RowFilter). Wenn du die Features nutzen willst könntest du vielleicht eine 1-spaltige JTable verwenden?


----------



## hdi (23. Okt 2011)

> Wäre glaube ich eleganter, wenn das Model die Daten behalten könnte und wirklich nur die Anzeige gefiltert wird.



Das Model _ist _die Anzeige. Du darfst dich da von dem Begriff nicht irritieren lassen. Ein List_Model _heißt nur deshalb so, da es eine Mapping des internen Daten_modells_ auf die Liste ist. Aber es geht trotzdem nur um die Anzeige. (Der Renderer kümmert sich um das _wie_). 



> Zur Zeit lösche ich bei jedem FilterEvent die daten aus dem ListModel und füge sie dann gefiltert wieder hinzu.


Wenn du irgendwas löscht oder hinzufügst ist da schon was falsch. DefaultListModel? Hört sich nach redundanter Speicherung deines internen Datenmodells an. Dein Datenmodell sollte dir alle Infos liefern können die du brauchst. Je nach Filterung lieferst du unterschiedliche Ergebnisse. Da bietet sich das Delegate Pattern ganz gut an:


```
public class MyListModel extends DefaultListModel{

     private Data data; // dein (gesamter) interner Datenbestand

     private ListModel model; // Delegate

     public static final int FILTER_INVOICE = 1;
     public static final int FILTER_CUSTOMER = 2;

     public void setFilter(int filter){
         switch(filter){
              case FILTER_INVOICE:
                   model = new InvoiceListModel();
                   break;
              case FILTER_CUSTOMER:
                   model = new CustomerListModel();
                   break;
              }
         }
     }

     @Override
     public int getSize(){
         return model.getSize(); // Delegation
     }

     // analog zu den anderen ListModel-Methoden

     private class InvoiceListModel implements ListModel{
 
          @Override
          public int getSize(){
               return data.getInvoices().size();
          }

          // etc
     }

     private class CustomerListModel implements ListModel{
 
          @Override
          public int getSize(){
               return data.getCustomers().size();
          }

          // etc
     }
}
```

Du hast deine new 
	
	
	
	





```
JList(new MyListModel())
```
, und das bleibt auch für die gesamte Laufzeit so. Über die setFilter-Methode kannst du die Anzeige durchschalten, und das ganz ohne dir irgendwelche Daten redundant abspeichern und dann irgendwie wieder löschen und neu zusammenbauen zu müssen etc.

edit: Das ganze geht auch noch etwas eleganter, zB kannst du das mit dem setFilter() besser lösen, und du musst auch nicht jedes mal eine neue Instanz des Invoice/CustomerModels erzeugen. Ist jetzt nur runtergeschrieben, aber ich denke die Idee kommt rüber.


----------



## vanny (23. Okt 2011)

setFilter muss ich sogar besser lösen ^^ weil man ja auch Kunden und Rechnungen zusammen listen kann^^

Der Ansatz is aber schon mal besser als meiner.

Gruß Vanny

//Edit: DefaultListModel?
Jain. Zum Testen Ja, hab aber schon ein eigenes in der Hinterhand es aber noch nicht implementiert, weil ich zZt. noch mit Datendummys arbeite.


----------



## vanny (24. Okt 2011)

Ich hätte da noch eine Frage.

Ich habe für die Filterfunktion neben der groben Filterung nach DatenTyp auch Unterfilterungen.
(Bei Rechnungen zBsp. erstellt, versendet, bezahlt, gemahnt und storniert)
Zudem kommt noch, das ich eine Flag setzen möchte, wenn der selektierte Eintrag aus der Liste geöffnet wurde.(soll halt eine intuitive Bedienung werden)

Nun denke ich, dass da ein oder mehr Interfaces Sinn machen 
Wenn ich zBsp. ein Interface MyListItems habe, dieses dann bei Costumer und Invoice implementiere, dann hab ich mit diesem Verfahren ne Menge Methoden im Costumer, die ich dort eigentlich nicht brauche.
Denn den werd ich wohl kaum stornieren:autsch:..ergo iwie redundant.

Mag sein, dass es heute einfach schon wieder zu spät ist und ich deshalb nur auf dem Schlauch stehe aber wie bekomme ich das kombiniert, so dass die überflüssigen Methoden rausfliegen , ich aber die Abstraktion nicht verliere.

Gruß Vanny


----------



## hdi (24. Okt 2011)

Hm, ich sehe da jetzt keinen Bedarf an Interfaces, sondern einfach an weiteren _Implementierungen_. So wie die o.g. Klassen InvoiceListModel und CustomerListModel, brauchst du halt noch PaidInvoiceListModel, SentInvoiceListModel, ... analog zu CustomerListModel. Gut, auf den ersten Blick vllt etwas lästig jetzt noch 10x ListModel zu implementieren.. Aber so ist es imho halt am besten. Du kannst so jederzeit neue Ansichten hinzufügen oder raushauen, und hast keine Abhängigkeiten zwischen den einzelnen Ansichten. Musst halt nur deine setFilter-Methode entsprechend anpassen. Mir fällt aber spontan keine bessere Idee ein.

Doof wird's, wenn du dann bezahlte UND versendete Rechungen anzeigen willst.. Das wird dann echt irgendwann zu krass mit den ListModels.. Aber was bleibt dir noch übrig? Kannst ansonsten nur irgenwelche Flags direkt in dein ListModel reinnehmen, und halt in den einzelnen Methoden wie getSize/getElement usw nur drauf switchen. ...Wobei, da war doch noch das *Decorator Pattern*. Wenn du solche Kombinationen vorhast, dann schau dir das mal an..



> Zudem kommt noch, das ich eine Flag setzen möchte, wenn der selektierte Eintrag aus der Liste geöffnet wurde.(soll halt eine intuitive Bedienung werden)


Darunter kann ich mir grad nix vorstellen. Was für ein Flag? Wozu soll das genau dienen?


----------



## vanny (24. Okt 2011)

hdi hat gesagt.:


> Darunter kann ich mir grad nix vorstellen. Was für ein Flag? Wozu soll das genau dienen?



Naja, wenn der User dann seine Rechnung mit Enter bestätigt, wird diese in ein entsprechendes Formular geladen und im eigentlichen Arbeitsbereich als Tab hinzugefügt.
Also benötige ich auch noch ein "active-flag", um zu verhindern, dass die Dinger mehrfach geöffnet werden und die Logik auf den Kopf stellen.
(Darstellung in der JList, Überwachung der Änderungen, Aktualisierung beim Schließen des Tabs usw.)

Das Decorator Pattern schau ich mir mal an.

//Edit: 


> Das Decorator Pattern kann eingesetzt werden, wenn:
> 
> ... einzelnen Objekten zusätzliches Verhalten und zusätzliche Eigenschaften hinzugefügt werden sollen, ohne andere Objekte zu beeinflussen.
> ... das Verhalten und die Eigenschaften auch wieder entfernt werden sollen.
> ...



Quelle

klingt nach mir 

So looong Vanny


----------

