0

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?

4

1 回答 1

2

这是一个关于如何组织逻辑的简短(原始!)示例。它在 SwingX 的上下文中(它支持 JList 的排序/过滤,就像 JTable 一样)因为我很懒 - 但你可以轻松地将它应用到你自己的环境中。

将您的条件视为可以打开或关闭的一组过滤器,然后将它们与 OR 组合(如果选择了一个或多个),如果没有选择则关闭。唯一的“技巧”是在其中一个被更改时评估所有复选框的状态:

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);
    }

}
于 2013-09-26T11:15:12.687 回答