Search code examples
javajtablerowfilter

JTable RowFilter not filtering initial invocation


No doubt this will be an easy fix, but as usual, I'm stumped.

I'm trying to filter out font family names that are non-renderable in a JTable using a JCheckBox. The JTable contains installed font family names (column 0), sample alphabet(column 1) and sample digits(column 2).

Columns one and two are rendered in their corresponding fonts and if the text in a cell cannot be renderered, the text is replaced with "non-renderable" using JTable.setValueAt(Object, int, int).

I then use then use "non-renderable" as the filter. However, only rows which are visible are filtered. When I scroll to the bottom of the table and apply the filter, the entire table is filtered as desired.

I also noticed, that when i move the horizontal divider, the divider doesnt repaint itself when it moves over the altered cells. Any help on this would also be appreciated.

import java.awt.*;
import java.awt.event.*;

import java.util.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

class run
{
    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                Viewer viewer = new Viewer();

                JFrame jframe = new JFrame();
                jframe.add(viewer);
                jframe.createBufferStrategy(1);
                jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                jframe.setLocation(50,50);
                jframe.pack();
                jframe.setVisible(true);
            }
        });
    }
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class Viewer extends JPanel
{
    final static long serialVersionUID = 0;

    String string_alphabet = "abcdefghijklmnopqrstuvwxyz";
    String string_digits = "0123456789";
    String string_punctuation = "`!:\";\',.-/(){}[]<>?";
    String string_symbols = "~@#$%^&*_+=|\\";

    String string_installedFontsColumnNames[] = {"installed fonts","sample","sample"};
    String string_installedFonts[];

    DefaultTableModel defaultTableModel_installedFonts;
    JTable jtable_installedFonts;

    JSplitPane jsplitPane_horizontal;
    JSplitPane jsplitPane_vertical;

    JCheckBox jcheckBox_nonRenderable;

    TableRowSorter<TableModel> tableRowSorter;

    public Viewer()
    {
        this.setLayout(new BorderLayout());

        JPanel jpanel_installedFonts = new JPanel(new BorderLayout());

        GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();

        string_installedFonts = graphicsEnvironment.getAvailableFontFamilyNames();

        Object object_tableData[][] = new Object[string_installedFonts.length][string_installedFontsColumnNames.length];

        for (int row = 0; row < object_tableData.length; row++)
        {
            Object object_columnData[] = new Object[string_installedFontsColumnNames.length];

            object_columnData[0] = string_installedFonts[row];
            object_columnData[1] = string_alphabet;
            object_columnData[2] = string_digits;

            object_tableData[row] = object_columnData;
        }

        defaultTableModel_installedFonts = new DefaultTableModel(object_tableData,string_installedFontsColumnNames);

        tableRowSorter = new TableRowSorter<TableModel>(defaultTableModel_installedFonts);

        jtable_installedFonts = new JTable(defaultTableModel_installedFonts);
        jtable_installedFonts.setRowSorter(tableRowSorter);

        jtable_installedFonts.getColumnModel().getColumn(0).setCellRenderer(new ColumnRenderer0());
        jtable_installedFonts.getColumnModel().getColumn(1).setCellRenderer(new ColumnRenderer1());
        jtable_installedFonts.getColumnModel().getColumn(2).setCellRenderer(new ColumnRenderer1());

        JScrollPane jscrollPane_installedFonts = new JScrollPane(jtable_installedFonts);

        jpanel_installedFonts.add(jscrollPane_installedFonts,BorderLayout.CENTER);

        JPanel jpanel_visibilityOptions = new JPanel(new GridLayout(1,2));
        jpanel_visibilityOptions.setBackground(Color.gray);

        JPanel jpanel_nonRenderable = new JPanel();
        jpanel_nonRenderable.setBackground(Color.lightGray);

        jcheckBox_nonRenderable = new JCheckBox("hide non-renderable fonts",false);
        jcheckBox_nonRenderable.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent actionEvent)
            {
                RowFilter<Object,Object> filter = null;

                if (jcheckBox_nonRenderable.isSelected())
                {
                    filter = RowFilter.notFilter(RowFilter.regexFilter("non-renderable"));
                }

                tableRowSorter.setRowFilter(filter);
            }
        });

        jpanel_nonRenderable.add(jcheckBox_nonRenderable,BorderLayout.CENTER);

        jpanel_visibilityOptions.add(new JPanel());
        jpanel_visibilityOptions.add(jpanel_nonRenderable);

        jpanel_installedFonts.add(jpanel_visibilityOptions,BorderLayout.SOUTH);

        jsplitPane_horizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,jpanel_installedFonts,new JPanel());
        jsplitPane_horizontal.setBorder(new EmptyBorder(0,0,0,0));

        jsplitPane_vertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT,jsplitPane_horizontal,new JPanel());
        jsplitPane_vertical.setBorder(new EmptyBorder(0,0,0,0));

        this.add(jsplitPane_vertical,BorderLayout.CENTER);
    }
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class ColumnRenderer0 implements TableCellRenderer
{
    JLabel jlabel;

    Color color_background;
    Color color_foreground;

    String string_cellText;

    public ColumnRenderer0()
    {
        jlabel = new JLabel();
        jlabel.setBorder(new EmptyBorder(0,2,0,2));
        jlabel.setHorizontalAlignment(JLabel.LEFT);
        jlabel.setOpaque(true);
    }

    public Component getTableCellRendererComponent(JTable jtable, Object object, boolean selected, boolean focus, int row, int column)
    {
        string_cellText = (String)object;

        if (selected)
        {
            color_background = jtable.getSelectionBackground();
            color_foreground = jtable.getSelectionForeground();
        }
        else
        {
            color_background = jtable.getBackground();
            color_foreground = jtable.getForeground();
        }

        jlabel.setText(string_cellText);
        jlabel.setBackground(color_background);
        jlabel.setForeground(color_foreground);

        return jlabel;
    }
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class ColumnRenderer1 implements TableCellRenderer
{
    JLabel jlabel;

    Color color_background;
    Color color_foreground;

    String string_cellText;
    String string_fontFamily;

    Font font;
    Font font_jtable;

    public ColumnRenderer1()
    {
        jlabel = new JLabel();
        jlabel.setBorder(new EmptyBorder(0,5,0,5));
        jlabel.setHorizontalAlignment(JLabel.CENTER);
        jlabel.setOpaque(true);
    }

    public Component getTableCellRendererComponent(JTable jtable, Object object, boolean selected, boolean focus, int row, int column)
    {
        string_cellText = (String)object;

        if (selected)
        {
            color_background = jtable.getSelectionBackground();
            color_foreground = jtable.getSelectionForeground();
        }
        else
        {
            color_background = jtable.getBackground();
            color_foreground = jtable.getForeground();
        }

        string_fontFamily = (String)jtable.getValueAt(row,0);

        font_jtable = jtable.getFont();

        font = new Font(string_fontFamily,Font.PLAIN,font_jtable.getSize());

        if (font.canDisplayUpTo(string_cellText) != -1)
        {
            font = new Font(font_jtable.getFamily(),Font.BOLD,font_jtable.getSize());
            string_cellText = "non-renderable";
            jtable.setValueAt(string_cellText,row,column);
            color_foreground = Color.red;

        }

        jlabel.setFont(font);
        jlabel.setText(string_cellText);
        jlabel.setBackground(color_background);
        jlabel.setForeground(color_foreground);

        return jlabel;
    }
}

Solution

  • The problem is, until the cell is rendered, the text remains what you initially set it to. Cells that are not visible are not rendered, therefore the model is not been updated. Filtering occurs at different times for different reasons.

    You should not be modifying the state of the model from within the renderer, but instead, should pre-determine if the font is renderedable or not when you built the table model and set the cell value accordingly...