Frage

I have a List, that included JPA Entity objects of a certain type. Their reference String values are displayed in a JList for the user to see.

I want my user to be able to select filters as JCheckBoxes in the UI such as 'only from Client x', or 'only of Type x' and dynamically filter the Entity List.

I had thought to just keep a copy of static List completeList; and static List filteredList; and then just run individual filter methods each time a new filter is selected in the UI to update filteredList, which would work fine until you have to un-select a single filter and leave the others selected (at which point it all falls apart).

Every situation I think through fall apart at one point or another, usually when trying to select multiple filters of from one Menu.

An example of my thought pattern that checks all the filters to determine what needs to go in the new JList;

public static void filterList(){
    List filteredList = new ArrayList<Job>(StoredDataClass.completeList);

    if(clientSmithsCheckBox.isSelected()){
        for(Job job : filteredList){
            if(!job.getClient.equals(clientSmithsCheckBox.getText())){
                filteredList.remove(job);
            }
        }
    }

    ....... // Check other filters here etc.

    if(clientBobAndCoCheckBox.isSelected()){
        for(Job job : filteredList){
            if(!job.getClient.equals(clientBobAndCoCheckBox.getText())){
                filteredList.remove(job);
            }
        }
    }

Even if clientBobAndCoCheckBox is selected, no jobs with that client will show in the final list, because we already removed them all because another client was already selected. Now, we could add to the list instead but we would face similar problems of having add stuff that shouldn't be there etc.

This is obviously possible, because this type of filtering system is common practice (example, excel). Although this is more of a design question, how can I achieve this?

War es hilfreich?

Lösung

Here's a short (and raw!) example of how you could organize your logic. It's in the context of SwingX (which supports sorting/filtering of a JList just the same way as a JTable) because I'm lazy - but you can apply it to your own environment easily.

Think of your criteria as a collection of filters which can be on or off, and then combine them with OR (if one or more is selected) or turn off if none is selected. The sole "trick" is to evaluate all of the checkboxes' states wheneven one of them is changed:

final JXList list = new JXList(new DefaultComboBoxModel(Locale.getAvailableLocales()));
list.setAutoCreateRowSorter(true);
final List<RowFilter> filters = new ArrayList<>();
filters.add(new MyRowFilter("de"));
filters.add(new MyRowFilter("ar"));
final List<JCheckBox> boxes = new ArrayList<>();
ActionListener l = new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        List<RowFilter<Object, Object>> orCandidates = new ArrayList<>();
        for (int i = 0; i < boxes.size(); i++) {
            if (boxes.get(i).isSelected())
                orCandidates.add(filters.get(i));
        }
        RowFilter<Object, Object> or = orCandidates.isEmpty() ? null :
            RowFilter.orFilter(orCandidates);
        list.setRowFilter(or);
    }

};
JCheckBox first = new JCheckBox("de");
first.addActionListener(l);
boxes.add(first);
JCheckBox second = new JCheckBox("ar");
second.addActionListener(l);
boxes.add(second);

JComponent content = new JPanel();
content.add(new JScrollPane(list));
for (JCheckBox box : boxes) {
    content.add(box);
}
showInFrame(content, "filters");

// just for completeness, the custom RowFilter
public static class MyRowFilter extends RowFilter {

    private String text;
    public MyRowFilter(String text) {
        this.text = text;
    }
    @Override
    public boolean include(Entry entry) {
        Locale locale = (Locale) entry.getValue(0);
        return locale.getLanguage().contains(text);
    }

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top