Rowfilter.regexFilter does not filter Date type columns in Jtable

Asked

Viewed 305 times

4

I have a JTable with a TableModel customized, and I’m trying to run a search field using JTextField. However, columns of the type Date and my class Cadastrante are not researched.

In my TableModel, I wrote the method getColumnClass() thus:

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case OFICIO:
                return Integer.class;
            case PROTOCOLO:
                return Long.class;
            case ASSUNTO:
                return String.class;
            case DATA:
                return Date.class;
            case CADASTRANTE:
                //Cadastrante é minha custom class
                return Cadastrante.class;
            default:
                return super.getColumnClass(columnIndex);
        }
    }

And the method getValueAt() is like this:

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    Oficio oficio = this.oficios.get(rowIndex);
    switch (columnIndex) {
        case OFICIO:
            return oficio.getCodigo();
        case PROTOCOLO:
            if (oficio.getProtocolo() == 0) {
                return null;
            }
            return oficio.getProtocolo();
        case ASSUNTO:
            return oficio.getAssunto();
        case DATA:
            // retorna um objeto do tipo util.Date  
            return oficio.getData();
        case CADASTRANTE:
            // retorna um objeto do tipo Cadastrante
            return oficio.getCadastrante();
        case SETOR:
            return oficio.getSetor().getNome();
    }
    return null;
}

On my main screen, where is the JTable, i start a variable of type TableRowSorter, passing the TableModel as an argument, and seto this variable as RowSorter of my table:

    this.linhasFiltradas = new TableRowSorter<TableModel>(this.tabela.getModel());
    this.tabela.setRowSorter(linhasFiltradas);

I added a Listener in the JTextField so that, when the ENTER is pressed, make the filter with the typed in that field:

private void fieldFiltroBarKeyReleased(java.awt.event.KeyEvent evt) {                                           
    if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
        JTextField field = (JTextField) evt.getSource();
        String busca = field.getText().trim();
        linhasFiltradas.setRowFilter(RowFilter.regexFilter("(?i)" + busca));
    }
}

In the columns I declared the guy as Date.class and Cadastrante.class, the search seems to ignore, even if I type terms displayed in these columns, for the others, the search usually locates.

In the case of my class Cadastrante, when debugging the corresponding section, I discovered that the RowSorter tries to invoke the method toString(), and since he doesn’t, he seems to ignore my class because he doesn’t know how to access her content. Overwriting this method within my class (return the name, it is displayed by the table’s Renderer), this column becomes searchable, but for the column that returns Date I couldn’t make it work.

Follow the chart Remaster:

public class OficioTableRenderer extends DefaultTableCellRenderer {

    private final int COLUNA_ASSUNTO = 2;
    private final int COLUNA_DATA = 3;
    private final int COLUNA_CADASTRANTE = 4;

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        switch (column) {
            case COLUNA_ASSUNTO:
                setHorizontalAlignment(SwingConstants.LEFT);
                setFont(new Font("Tahoma", 0, 11));
                break;
            case COLUNA_DATA:
                setText(new SimpleDateFormat("dd/MM/yyyy").format(value));
                setHorizontalAlignment(SwingConstants.CENTER);
                setFont(new Font(null, 0, 14));
                break;
            case COLUNA_CADASTRANTE:
                Cadastrante cad = (Cadastrante) value;
                setText(cad.getNome());
                setHorizontalAlignment(SwingConstants.CENTER);
                setFont(new Font(null, 0, 14));
                break;
            default:
                setHorizontalAlignment(SwingConstants.CENTER);
                setFont(new Font(null, 0, 14));
                break;
        } 
        setForeground(Color.black);
        return this;
    }

    @Override
    protected void setValue(Object value) {
        super.setValue(value); 
    }      
}

How do I make the column Date searchable as well?

  • How is the method getValueAt(int rowIndex, int columnIndex) of his TableModel?

  • @Victorstafusa added in question the method .

  • How Your Renderer Works?

  • @Victorstafusa added the question. In the case of the Date column, I apply the BR format mask and the date usually appears as dd/MM/yyyy. Without the Remaster, the date is displayed in American format, with dashes.

1 answer

3


The solution would be to use a custom class to encapsulate the Date:

public class DateHelper implements Comparable<DateHelper> {
    private final Date date;

    private DateHelper(Date date) {
        this.date = date;
    }

    public static DateHelper of(Date date) {
        return date == null ? null : new DateHelper(date);
    }

    @Override
    public int compareTo(DateHelper other) {
        return date.compareTo(other.date);
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof DateHelper)) return false;
        return date.equals(((DateHelper) other).date);
    }

    @Override
    public int hashCode() {
        return date.hashCode();
    }

    @Override
    public String toString() {
        return new SimpleDateFormat("dd/MM/yyyy").format(date);
    }

    public Date getDate() {
        return date;
    }
}

This will bring about some changes in your TableModel:

@Override
public Class<?> getColumnClass(int columnIndex) {
    switch (columnIndex) {
        case OFICIO:
            return Integer.class;
        case PROTOCOLO:
            return Long.class;
        case ASSUNTO:
            return String.class;
        case DATA:
            return DateHelper.class;
        case CADASTRANTE:
            //Cadastrante é minha custom class
            return Cadastrante.class;
        default:
            return super.getColumnClass(columnIndex);
    }
}

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    Oficio oficio = this.oficios.get(rowIndex);
    switch (columnIndex) {
        case OFICIO:
            return oficio.getCodigo();
        case PROTOCOLO:
            if (oficio.getProtocolo() == 0) {
                return null;
            }
            return oficio.getProtocolo();
        case ASSUNTO:
            return oficio.getAssunto();
        case DATA:
            // retorna um objeto do tipo DateHelper 
            return DateHelper.of(oficio.getData());
        case CADASTRANTE:
            // retorna um objeto do tipo Cadastrante
            return oficio.getCadastrante();
        case SETOR:
            return oficio.getSetor().getNome();
    }
    return null;
}

And finally, in his Remair:

        case COLUNA_DATA:
            setHorizontalAlignment(SwingConstants.CENTER);
            setFont(new Font(null, 0, 14));
            break;
  • What is other.date? You are accessing the private property of the class of another object of the same type?

  • @Diegof Yes. You are accessing the field date of the other object of the same class.

  • The fact that he’s private does not prevent access?

  • 1

    @Diegof No, because access restriction rules are based on classes and not on instances. Since it is another object of the same class, then this is allowed.

  • Thank you, you answered perfectly and I didn’t even have to change anything in setValueAt nor in class Oficio :)

  • Victor, how do I retrieve the Date from a Datehelper? I found a situation in the code where I needed to get the Date, then Classcastexception burst because of the different classes.

  • @Diegof Just put a getter on it. I edited the answer to have that too.

  • 1

    I managed to return, made a method public Date parse(){return date;} and resolved.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.