Pregunta

everyone. I decided to contribute with this topic after racking my brains exhaustively.

Most part of the filtering code I got from:

Software used:

  • MySQL 14.14
  • JDK 7
  • NetBeans 7.1.2

Suppose we have the following example table called "table":

+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| name      | varchar(50) | YES  |     | NULL    |                |
| phone     | varchar(20) | YES  |     | NULL    |                |
| birthdate | datetime    | YES  |     | NULL    |                |
| status    | int(1)      | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+

Creating a view called "vTable", considering a list that will display only the ID, the name and the birth date:

CREATE VIEW vTable AS
SELECT id, name, birthdate FROM table WHERE status IS NOT NULL;

I'm using MVC pattern, so there are packages "model", "view" and "controller".

Creating the data access object TableDAO:

package model.DAO;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.VO.TableDAO;
import model.VO.VTableVO;

public class TableDAO extends ConnectionDAO {

    public List<VInstituicaoVO> List() throws ClassNotFoundException {

        List<VTableVO> listTable = new ArrayList<>();
        try {
            openConnection();
            con.setAutoCommit(false);
            PreparedStatement stmt = con.prepareCall(
                    "SELECT id, name, birthdate FROM vTable");
            ResultSet record = stmt.executeQuery();

            while(record.next()) {
               VTableVO  vo = new VTableVO();
               vo.setId(record.getInt(1));
               vo.setName(record.getString(2));
               vo.setBirthdate(record.getDate(3));
               listTable.add(vo);
            }

            closeConnection();

        } catch (SQLException ex) {
            Logger.getLogger(TableDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return listTable;
}

Creating the value-object (don't forget to generate getters and setters) TableVO:

package model.VO;

import java.sql.Date;

public class TableVO {

    private Integer id;
    private String name;
    private String phone;
    private Date birthdate;
    private int status;

    public TableVO() {}

    public TableVO(ITableVO vo) {

        id = vo.getId();
        name = vo.getName();
        phone = vo.getPhone();
        birthdate = vo.getBirthdate();
        status = vo.getStatus();

    }

   // GENERATE GETTERS AND SETTERS

}

VTableVO class:

package model.VO;

import java.sql.Date;

public class VTableVO {

    private Integer id;
    private String name;
    private Date birthdate;

// GENERATE GETTERS AND SETTERS

}

ITableDAO interface:

package model.DAO;

import java.util.List;
import model.VO.TableVO;

public interface ITableDAO {

    public List<TableVO> List();

}

ITableVO interface:

package model.VO;

import java.sql.Date;

public interface ITableVO {

    public Integer getId();
    public void setId(Integer set_id);

    public String getName();
    public void setName(String set_nome);

    public String getPhone();
    public void setPhone(String set_phone);

    public Date getBirthdate();
    public void setBirthdate(Date set_birthdate);

    public Integer getStatus();
    public void setStatus(Integer set_status);

}

With this structure, how could we implement a search function in a JTable?

¿Fue útil?

Solución

Inside the form where data must be displayed, we create two JPanels:

  1. where we'll put 3 JTextFields ("txtId", "txtName" and "txtBirthdate")
  2. where we'll put the JTable "TableExample"

I'll do it only for the first JTextField, that is, "txtId".

FrmExample form (NOTE: there's an internal class called CustomRenderer at the end - to color the border of the cell which was found):

package view;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Date;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.table.*;
import model.DAO.TableDAO;
import model.VO.VTableVO;

public class FrmExample extends javax.swing.JInternalFrame {

    public FrmExample() throws SQLException, ClassNotFoundException {

        initComponents();
        getTableModel();
        getTable();
        txtId.addActionListener(new ActionListener() {      
            @Override
            public void actionPerformed(ActionEvent e) {
                searchId();
            }
        });
        TableExample.setAutoCreateRowSorter(true);

    }

    private  void getTableModel() {

        // Configure the columns of JTable
        TableColumnModel columnModel =
                this.TableExample.getColumnModel();

        columnModel.getColumn(0).setHeaderValue("ID");
        columnModel.getColumn(0).setPreferredWidth(60);

        columnModel.getColumn(1).setHeaderValue("Name");
        columnModel.getColumn(1).setPreferredWidth(180);

        columnModel.getColumn(2).setHeaderValue("Birth Date");
        columnModel.getColumn(2).setPreferredWidth(180);

    }

    private JTable getTable() throws ClassNotFoundException {

        String[] columnTitles = { "ID", "Name", "Birth Date" };
        List<VTableVO> listExample = new TableDAO().List();
        Object[][] data = new Object[listExample.size()][columnTitles.length];

        for(VTableVO vo : list) {
                    data[list.indexOf(vo)][0] = "" + vo.getId();
                    data[list.indexOf(vo)][1] =      vo.getName();
                    data[list.indexOf(vo)][2] = "" + vo.getBirthdate();
        } // Is there a way to code that so it become more dynamic? Writing 1 line instead of 3

        DefaultTableModel model = new DefaultTableModel(data, columnTitles) {
            @Override
            public Class getColumnClass(int col) {
                Object obj = getValueAt(0, col);
                if(obj == null)
                    return Object.class;
                else
                    return obj.getClass();
            }
        };

        TableExample.setDefaultRenderer(String.class, new CustomRenderer());
        TableExample.setRowSelectionAllowed(true);
        TableExample.setColumnSelectionAllowed(true);
        TableExample.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        TableExample.setModel(model);

        TableModel model = TableExample.getModel();
        final TableRowSorter<TableModel> sorter = new TableRowSorter<>(model);
        TableExample.setRowSorter(sorter);

        return TableExample;

    }

    private void searchId() {

        String target = txtId.getText();
        for(int row = 0; row < TableExample.getRowCount(); row++) {
            String next = (String)TableExample.getValueAt(row, 0); // First row only
                if(next.equals(target)) {
                    displayResultSearch(row, 0);
                    return;
                }
        }

        CustomRenderer renderer = (CustomRenderer)TableExample.getDefaultRenderer(String.class);
        renderer.setTargetCell(-1, -1);
        TableExample.repaint();

    }

    private void displayResultSearch(int row, int column) {
        CustomRenderer renderer = (CustomRenderer)TableExample.getCellRenderer(row, column);
        renderer.setTargetCell(row, column);
        Rectangle rect = TableExample.getCellRect(row, column, false);
        TableExample.scrollRectToVisible(rect);
        TableExample.repaint();
    }

class CustomRenderer implements TableCellRenderer {

    JLabel label;
    int targetRow, targetColumn;

    public CustomRenderer() {

        label = new JLabel();
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setOpaque(true);
        targetRow = -1;
        targetColumn = -1;

    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
    boolean isSelected, boolean hasFocus, int row, int column) {

        if(isSelected) {
            label.setBackground(table.getSelectionBackground());
            label.setForeground(table.getSelectionForeground());
        } else {
            label.setBackground(table.getBackground());
            label.setForeground(table.getForeground());
        }
        if(row == targetRow && column == targetColumn) {
            label.setBorder(BorderFactory.createLineBorder(Color.red)); // Color it in RED!
            label.setFont(table.getFont().deriveFont(Font.BOLD)); // And BOLD!
        } else {
            label.setBorder(null);
            label.setFont(table.getFont());
        }
        label.setText((String)value);
        return label;

    }

    public void setTargetCell(int row, int column) {

        targetRow = row;
        targetColumn = column;

    }

  }

}

To search something you must type in the selected field, then HIT ENTER. I'm not using a JButton in this example.

To implement the same for other columns, the biggest hint I give is changing the following lines:

  • String next = (String)TableExample.getValueAt(row, column number here);
  • displayResultSearch(row, column number here);

I hope that will help a lot of people. If anyone find anything worth changing, for any reason at all, please answer with all considerations. Thanks!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top