简体   繁体   中英

button to filter JTable for checkbox is selected

I have a JTable fairly similar to this one.

http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#sorting

表

I have managed to set a normal filter on it (a search function) and it works well. I want to have a button that will immediately show only the rows where Vegetarian is checked.

Ok so now thanks to the help given by @peeskillet and @HovercraftFullOfEels, this is the solution to my problem:

final TableRowSorter<MovieReviewTableModel> rowSorter = new TableRowSorter<MovieReviewTableModel>(tableModel);



// custom RowFilter 
            RowFilter<MovieReviewTableModel, Integer> filter = new RowFilter<MovieReviewTableModel, Integer>()
            {
                // include method returns true to show the row and false to not show it
                @Override
                public boolean include(RowFilter.Entry<? extends MovieReviewTableModel, ? extends Integer> entry)
                {
                    int modelRow = entry.getIdentifier(); //row index
                    boolean checked = ((Boolean)entry.getModel().getValueAt(modelRow, 3)).booleanValue();
                    System.out.println(checked); // to test the values coming through
                    return checked;
                }

            };

            table.setRowSorter(rowSorter);

            JButton onlyFeatured = new JButton("Only show Featured");
            threeButtonPanel.add(onlyFeatured);

            onlyFeatured.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent event)
                {
                    rowSorter.setRowFilter(filter);
                }
            });

It works! Thanks so much guys, I owe you drinks or something. :D

Let's revisit the tutorial How to Use Tables: Sorting and Filtering .

In addition to reordering the results, a table sorter can also specify which rows will be displayed. This is known as filtering. TableRowSorter implements filtering using javax.swing.RowFilter objects. RowFilter implements several factory methods that create common kinds of filters.

Things to look at:

  • TableRowSorter . - We know we're going to need this.
  • Oh, they gave us a link to RowFilter docs. Let's open that up in a new browser tab.
  • But first the last line " RowFilter implements several factory methods that create common kinds of filters." . We should probably look to see what those "common kinds" are.

RowFilter javadoc

  • Static methods - andFilter , dateFilter , notFilter , numberFilter , orFilter , regexFilter . Ok, I recognize the regexFilter from the tutorial. But those others, just by their names alone, don't sound too promising. Maybe we should implement our own. Let's look at the rest of the javadoc

javax.swing.RowFilter<M,I>

Type Parameters:
M - the type of the model; for example PersonModel
I - the type of the identifier; when using TableRowSorter this will be Integer

Ok so from this we know two thing. When we create our custom RowFilter , we should pass a TableModel type as the first parameter, and type Integer to represent the row number.

RowFilter is used to filter out entries from the model so that they are not shown in the view. For example, a RowFilter associated with a JTable might only allow rows that contain a column with a specific string. The meaning of entry depends on the component type. For example, when a filter is associated with a JTable , an entry corresponds to a row; when associated with a JTree , an entry corresponds to a node.

Subclasses must override the include method to indicate whether the entry should be shown in the view. The Entry argument can be used to obtain the values in each of the columns in that entry

So based on those two paragraghs, we know the RowFilter is used to filter out rows we don't want in the view, and that if we create our own, we will need to override the include method to return whether a row should be shown or not. And also the include method will have an Entry argument, from which we can obtain details that may be o interest to us, when determining which row to not return true on. Here's the basic example (guideline) the javadoc gives us

RowFilter<TableModel, Integer> filter = new RowFilter<TableModel, Integer>() {
    @Override
    public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
        // do your logic here to return true or false.
    }
};

Cool, but what is this RowFilter.Entry class, and what interesting information can it provide to us? Let's look at the javadoc .

One interesting thing we can see is the getModel() method. From that we can get our table model. So let's finish the implementation

private static final int CHECKBOX_COLUMN = 4;
...
RowFilter<TableModel, Integer> filter = new RowFilter<TableModel, Integer>() {
    @Override
    public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
        int modelRow = entry.getIdentifier();
        Boolean checked = (Boolean)entry.getModel().getValueAt(modelRow, CHECKBOX_COLUMN);
        return checked;
    }
};

Not much too it. Now all that's left is setting the filter to the sorter, as you learned from the Oracle tutorial already, using the regex filter.

Here's a fill demo code. It doesn't implement the ActionListener for the button press. I didn't want to do everything for you. You should have enough information to handle that on your own :-D Happy Learning!

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class TableBooleanFilterDemo {

    public TableBooleanFilterDemo() {
        JTable table = getTable();
        TableRowSorter<TableModel> rowSorter = new TableRowSorter<>(table.getModel());
        RowFilter filter = getRowFilter();
        rowSorter.setRowFilter(filter);
        table.setRowSorter(rowSorter);

        JFrame frame = new JFrame();
        frame.add(new JScrollPane(table));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private static final int CHECKBOX_COLUMN = 4;

    private RowFilter getRowFilter() {
        RowFilter<TableModel, Integer> filter = new RowFilter<TableModel, Integer>() {
            @Override
            public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
                int modelRow = entry.getIdentifier();
                Boolean checked = (Boolean)entry.getModel().getValueAt(modelRow, CHECKBOX_COLUMN);
                return checked;
            }
        };
        return filter;
    }

    private JTable getTable() {
        Object[][] data = {
            {"Kathy", "Smith",
                "Snowboarding", new Integer(5), new Boolean(false)},
            {"John", "Doe",
                "Rowing", new Integer(3), new Boolean(true)},
            {"Sue", "Black",
                "Knitting", new Integer(2), new Boolean(false)},
            {"Jane", "White",
                "Speed reading", new Integer(20), new Boolean(true)},
            {"Joe", "Brown",
                "Pool", new Integer(10), new Boolean(false)}
        };
        String[] columnNames = {"First Name",
            "Last Name",
            "Sport",
            "# of Years",
            "Vegetarian"};
        return new JTable(new DefaultTableModel(data, columnNames) {
            public Class getColumnClass(int c) {
                return getValueAt(0, c).getClass();
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new TableBooleanFilterDemo();
            }
        });
    }
}

To be honest, I've never had to implement my own RowFilter , but the above is the process I pretty much go through when trying to learn something new. Took me longer to write this answer, then to learn how to do it. Gotta learn to read documentation, not just tutorials. Tutorials are a good starting point, but once you get to more complicated matters, you need to dig deeper. Same with any new technology you want to learn.

Your RowFilter is too simplistic, and instead you need to give it more heft, more meat. The RowFilter API actually has a small bit of very useful example code that could help you. For example, I used that code to help my create a very simplistic but workable RowFilter:

import java.awt.BorderLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

public class Foo {
   public static void main(String[] args) {
      String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
      JComboBox<String> petCombo = new JComboBox<>(petStrings);
      String[] columnNames = {"Name", "Animal", "Male", "Delete"};
      Object[][] data = {
          {"Tweetie", petStrings[0], false, null},
          {"Sylvester", petStrings[1], true, null},
          {"Lassie", petStrings[2], false, null},
          {"Peter", petStrings[3], true, null},
          {"Arnold", petStrings[4], true, null}
      };

      final MyTableModel model = new MyTableModel(data, columnNames);
      final JTable table = new JTable(model);
      table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(petCombo));


      final TableRowSorter<MyTableModel> sorter = new TableRowSorter<MyTableModel>(model);
      final RowFilter<MyTableModel,Integer> maleSexFilter = new RowFilter<MyTableModel,Integer>() {
         public boolean include(Entry<? extends MyTableModel, ? extends Integer> entry) {
            MyTableModel personModel = entry.getModel();
            boolean maleSex = ((Boolean) personModel.getValueAt(entry.getIdentifier(), 2)).booleanValue();
           return maleSex;
          }
        };

      sorter.setRowFilter(null);
      table.setRowSorter(sorter);

      JToggleButton showMalesButton = new JToggleButton("Show Males");
      showMalesButton.addItemListener(new ItemListener() {

         @Override
         public void itemStateChanged(ItemEvent iEvt) {
            if (iEvt.getStateChange() == ItemEvent.SELECTED) {
               System.out.println("selected!");
               sorter.setRowFilter(maleSexFilter);
            } else {
               sorter.setRowFilter(null);
            }
         }
      });

      JPanel bottomPanel = new JPanel();
      bottomPanel.add(showMalesButton);

      JPanel panel = new JPanel(new BorderLayout());
      panel.add(new JScrollPane(table), BorderLayout.CENTER);
      panel.add(bottomPanel, BorderLayout.PAGE_END);

     JOptionPane.showMessageDialog(null, panel);
   }
}

@SuppressWarnings("serial")
class MyTableModel extends DefaultTableModel {
   public MyTableModel(Object[][] data, String[] columnNames) {
      super(data, columnNames);
   }

   @Override
   public Class<?> getColumnClass(int columnIndex) {
      if (columnIndex == 2) {
         return Boolean.class;
      }
      return super.getColumnClass(columnIndex);
   }
}

The filter code is:

  final RowFilter<MyTableModel,Integer> maleSexFilter = new RowFilter<MyTableModel,Integer>() {
     public boolean include(Entry<? extends MyTableModel, ? extends Integer> entry) {
        MyTableModel personModel = entry.getModel();
        boolean maleSex = ((Boolean) personModel.getValueAt(entry.getIdentifier(), 2)).booleanValue();
       return maleSex;
      }
    };

where all I do is get the boolean value held by the 2nd column, row determined by entry.getIdentifier(), and return that value. If true, then it is selected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM