How to popular a Jtable with own Tablemodel?

Asked

Viewed 4,373 times

11

When you’re messing with , we almost always come across having to handle tables and populate them with some kind of information. For simpler situations, the DefaultTableModel resolves, but when you have a personalized object, the recommendation we receive from the most experienced is to create the own TabelModel.

How can I popular a JTable with a TableModel own, using this object class, for example?

public class Funcionario {

    private String nome;
    private int idade;
    private int matricula;
    private boolean admitido;

    public Funcionario(String nome, int idade, int matricula) {
        this.nome = nome;
        this.idade = idade;
        this.matricula = matricula;
        this.admitido = true;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public int getMatricula() {
        return matricula;
    }

    public void setMatricula(int matricula) {
        this.matricula = matricula;
    }

    public boolean isAdmitido() {
        return admitido;
    }

    public void setAdmitido(boolean admitido) {
        this.admitido = admitido;
    }
}

1 answer

16


Introducing

To Create a Tablemodel, it is necessary to extend the class AbstractTableModel, which is an abstract class with the main functionalities necessary to work with the table completion. We can also implement the interface TableModel, but the first option already implements it, adding other features that makes it more complete for the case.


Main methods of the Abstracttablemodel class

Before creating a TableModel, it is important to understand the workings of some of the methods we will use:

  • isCellEditable(int rowIndex, int columnIndex) = receives the cell coordinates(row and column) and returns a boolean that will indicate whether the cell content is editable or not;

  • getRowCount() = returns the total of rows the table has;

  • getColumnCount() = returns the total of columns the table has;

  • getColumnName(int column) = receives an index and returns the name of the column of that given input;

  • getColumnClass(int columnIndex) = receives a column index and returns the data type of the cells in that column;

  • getValueAt(int rowIndex, int columnIndex) = this method is that will fill the table, cell by cell, according to its coordinates(row and column).

  • setValueAt(Object aValue, int rowIndex, int columnIndex) = this method will be called whenever a cell is changed in the table.

  • fireTableDataChanged() = shall notify all listeners that there has been a change in the table and that it should be redrawn.

With these methods, we can already create a basis of TableModel so that the table knows how to fill in with objects of the type Funcionario.


Creating the Tablemodel

We will create the class FuncionarioTableModel, you will receive a list of objects:

import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;

public class FuncionarioTableModel extends AbstractTableModel {

    //aqui transformei em coluna cada propriedade de Funcionario
    //que eu quero que seja exibida na tabela  
    private String colunas[] = {"nome", "idade", "matricula", "admitido"};
    private ArrayList<Funcionario> funcionarios;
    private final int COLUNA_NOME = 0;
    private final int COLUNA_IDADE = 1;
    private final int COLUNA_MATRICULA = 2;
    private final int COLUNA_ADMITIDO = 3;

    public FuncionarioTableModel(ArrayList<Funcionario> funcionarios) {
        this.funcionarios = funcionarios;
    }

    //retorna se a célula é editável ou não
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }
    
    //retorna o total de itens(que virarão linhas) da nossa lista
    @Override
    public int getRowCount() {
        return funcionarios.size();
    }
    //retorna o total de colunas da tabela
    @Override
    public int getColumnCount() {
        return colunas.length;
    }
    //retorna o nome da coluna de acordo com seu indice
    @Override
    public String getColumnName(int indice) {
        return colunas[indice];
    }

    //determina o tipo de dado da coluna conforme seu indice
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case COLUNA_NOME:
                return String.class;
            case COLUNA_IDADE:
                return Integer.class;
            case COLUNA_MATRICULA:
                return Integer.class;
            case COLUNA_ADMITIDO:
                return Boolean.class;
            default:
                return String.class;
        }
    }

    //preenche cada célula da tabela
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Funcionario funcionario = this.funcionarios.get(rowIndex);

        switch (columnIndex) {
            case COLUNA_NOME:
                return funcionario.getNome();
            case COLUNA_IDADE:
                return funcionario.getIdade();
            case COLUNA_MATRICULA:
                return funcionario.getMatricula();
            case COLUNA_ADMITIDO:
                return funcionario.isAdmitido();
        }
        return null;
    }
    //altera o valor do objeto de acordo com a célula editada
    //e notifica a alteração da tabela, para que ela seja atualizada na tela
    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //o argumento recebido pelo método é do tipo Object
        //mas como nossa tabela é de funcionários, é seguro(e até recomendável) fazer o cast de suas propriedades
        Funcionario funcionario = this.funcionarios.get(rowIndex);
        //de acordo com a coluna, ele preenche a célula com o valor
        //respectivo do objeto de mesmo indice na lista
        switch (columnIndex) {
            case COLUNA_NOME:
                funcionario.setNome(String.valueOf(aValue));
                break;
            case COLUNA_IDADE:
                funcionario.setIdade((int) aValue);
                break;
            case COLUNA_MATRICULA:
                funcionario.setMatricula((int) aValue);
                break;
            case COLUNA_ADMITIDO:
                funcionario.setAdmitido((boolean) aValue);
        }
        //este método é que notifica a tabela que houve alteração de dados
        fireTableDataChanged();
    }
}

The code is commented on what each method is doing. Set constants as column index for code to be easier to understand, and columns are already defined in a list of String, but can adapt as you like, either by passing a list of columns, as happens with the DefaultTableModel, or set directly in the method getColumnName, but I believe that this is unnecessary complexity for this example.


Filling Jtable with the Tablemodel

Once ready, there are two ways to pass this Tablemodel to the table: passing directly to the Jtable constructor by instantiating it or passing the model via method setModel(). Obviously, when creating the table, the first option is the one that should be used:

import java.awt.EventQueue;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class JTableExample extends JFrame {

    private JTable tabela;
    private JScrollPane scrollPainel;

    public JTableExample() {
        renderizarTela();
    }

    private void renderizarTela() {
        
        //4 ojetos criados para popular a tabela
        Funcionario f1 = new Funcionario("Roberto", 33, 1220);
        Funcionario f2 = new Funcionario("Diego", 25, 1615);
        Funcionario f3 = new Funcionario("Afonso", 25, 1458);
        Funcionario f4 = new Funcionario("Sergio", 42, 1165);

        ArrayList<Funcionario> funcionarios = new ArrayList<>();
        funcionarios.add(f1);
        funcionarios.add(f2);
        funcionarios.add(f3);
        funcionarios.add(f4);

        //cria um objeto do nosso model
        FuncionarioTableModel model = new FuncionarioTableModel(funcionarios);
        
        //instancia a tabela já com o model como argumento
        this.tabela = new JTable(model);
        this.scrollPainel = new JScrollPane(tabela);

        this.add(scrollPainel);
        this.pack();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JTableExample tb = new JTableExample();
                tb.setLocationRelativeTo(null);
                tb.setVisible(true);
            }
        });
    }
}

And the result:

print da tabela em execução

The most interesting thing is that, because we have defined the type in each column, it is not necessary to worry about problems of cast numerical. For example, pass letters as age or matricula, the table already restricts itself to this and does not accept a data that is not of that type. Of course, if you pass a number as a name, it will not be stopped since it will be understood as String.


Completion

The class AbstractTableModel has other methods to make the table much more powerful, and still can add other features like deletion and addition of lines, do operations with database, but will not be deepened by didactic issues.

From the above, one can see that it is not so complicated to implement a TableModel, not to mention that it facilitates the maintainability of the code and makes our table much more flexible than using DefaultTableModel.

Of course this is applicable to cases with less complexity, or for academic purposes, since there are components that facilitate and even automate this creation (such as examples cited by Anthony Accioly), but it is important to understand its functioning to know how to handle this component.

  • 2

    Only for educational purposes, while implementing a TableModel in nail is certainly an interesting exercise, in practice in 99% of cases are met by generic Frameworks such as Jgoodies Binding, Beans Binding and Glazed Lists with your own templates. In the Javafx world TableView, TableColumn and ObservableList also replaced the model-based architecture. In practice it is rare to need to implement a TableModel.

  • Very good... Great code and explanations. Used in Netbeans. .Bingo... Perfect I made several BEANS and DAOS.. Quiet.. Success.... Luciano Deluqui

Browser other questions tagged

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