How popular is a JTable with TableModel itself?

12

When you're messing with

asked by anonymous 04.04.2016 / 16:35

1 answer

18

Introduction

To create a Tablemodel , you need to extend the < strong> AbstractTableModel , which is an abstract class with the main functionalities needed to work with table fills. We can also implement the TableModel , but the first option already implements it, adding other features that make it more complete for the case.

Main methods of the AbstractTableModel class

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

  • isCellEditable(int rowIndex, int columnIndex) = returns the total number of rows the table has;

  • getRowCount() = returns the total columns that the table has;

  • getColumnCount() = receives an index and returns the column name of that index entered;

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

  • getColumnClass(int columnIndex) = This method will fill the table, cell by cell, according to its coordinates (row and column).

  • getValueAt(int rowIndex, int columnIndex) = This method will be called whenever a cell is changed in the table.

  • setValueAt(Object aValue, int rowIndex, int columnIndex) = will notify all% of% that there has been a change in the table and that it should be redrawn.

With these methods, we can already create a base of fireTableDataChanged() so that the table knows how to fill with objects of type listeners .

Creating the TableModel

We will create the class TableModel , which 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. I set constants as the index of the columns so the code is easier to understand, and the columns are already defined in a Funcionario list, but you can adapt as you want, either by passing a list of columns, as with FuncionarioTableModel , or set directly in the String method, but I believe this is unnecessary complexity for this example.

Filling the JTable with TableModel

Once done, there are two ways to pass this TableModel to the table: passing directly to the JTable constructor when instantiating it or passing the model via DefaultTableModel method. 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:

Themostinterestingthingisthat,becausewehavedefinedthetypeineachcolumn,wedonothavetoworryaboutnumericcastproblems.Forexample,passingletterssuchasageorenrollment,thetableisalreadyrestrictedinthisanddoesnotacceptadatathatisnotofthattype.Ofcourse,ifyoupassanumberasaname,itwillnotbepreventedsinceitwillbeunderstoodasgetColumnName.

Conclusion

ThesetModel()classhasothermethodstomakethetablemuchmorepowerful,andyoucanaddotherfeaturessuchasdeletingandaddingrows,doingdatabaseoperations,butitwillnotbedeepenedbydidacticissues.

Fromtheabove,youcanseethatitisnotsocomplicatedtoimplementaString,nottomentionthatitfacilitatesthemaintainabilityofthecodeandmakesourtablemuchmoreflexiblethanusingAbstractTableModel.

Ofcoursethisappliestocaseswithlesscomplexity,orforacademicpurposes,sincetherearecomponentsthatfacilitateandevenautomatethiscreation(suchasexamples quoted by Anthony Accioly ), but it is important to understand how it works to know handle this component.

    
04.04.2016 / 16:35