quarta-feira, 6 de junho de 2012

Crie seu próprio TableModel 2

Olá pessoal.
Anteriormente vimos qual a vantagem de se implementar nosso próprio TableModel. Como dito, iremos agora fazer alguma melhorias em nosso exemplo. Hoje vamos implementar as operações básicas (adicionar ,editar, excluir) em nossa tabela.
Inicialmente vamos adicionar o código abaixo no método FuncionarioTableModel.

public void adicionar(Funcionario funcionario){
        listaFuncionario.add(funcionario);
        this.fireTableRowsInserted(listaFuncionario.size() - 1, listaFuncionario.size() - 1);
    }
 
    public void excluir(int row){
        listaFuncionario.remove(row);
        this.fireTableRowsDeleted(row, row);
    }
 
    public void atualizar(int row, Funcionario funcionario){
        listaFuncionario.set(row, funcionario);
        this.fireTableRowsUpdated(row, row);
    }
 
    public Funcionario getFuncionario(int row){
        return listaFuncionario.get(row);
    }

Note que nos métodos adicionar, excluir e atualizar existe um disparo de métodos do AbstractTableModel. Isto se faz necessário para forçar que a renderização seja refeita naquela linha para aquela operação. Se não existirem estes disparos, o item pode ficar visualmente no seu estado antigo porém na lista do model estará o item modificado.

A classe TableModelTeste sofreu várias alterações como segue:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import net.miginfocom.swing.MigLayout;

public class TableModelTeste extends JFrame implements ActionListener {

    private JTable tableFuncionario;
    private JScrollPane scrollPane;
    private List<Funcionario> listaFuncionarios;
    private JTextField nome;
    private JTextField idade;
    private JComboBox departamento;
    private JComboBox cargo;
    private JPanel panel;
    private JButton novo;
    private JButton salvar;
    private JButton excluir;
    private boolean nv = true;

    public TableModelTeste() {
        init();
    }

    final void init() {
        this.setTitle("Exemplo de TableModel");
        //populando a lista para inserir no table
        this.listaFuncionarios = new LinkedList<Funcionario>();
        this.listaFuncionarios.add(new Funcionario("Marlon Meneses", 26, "Centro Tecnologico", "Desenvolvedor"));
        this.listaFuncionarios.add(new Funcionario("Fulano Teste", 21, "Centro Tecnologico", "Estagiario"));
        this.listaFuncionarios.add(new Funcionario("Siclano Anonimo", 32, "Recepcao", "Auxiliar Administrativo"));
        this.listaFuncionarios.add(new Funcionario("Beltrano Nao Sei O Nome", 30, "Centro Tecnologico", "Gerente de Projetos"));
        //adicionando no table
        this.tableFuncionario = new JTable(new FuncionarioTableModel(this.listaFuncionarios));
        this.tableFuncionario.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        this.tableFuncionario.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                listaMouseClick(e);
            }
        });
        this.scrollPane = new JScrollPane(this.tableFuncionario);

        this.nome = new JTextField();
        this.idade = new JTextField();
        this.departamento = new JComboBox(new String[]{"Centro Tecnologico", "Recepcao", "Administracao", "RH"});
        this.cargo = new JComboBox(new String[]{"Desenvolvedor", "Estagiario", "Gerente de Projetos", "Auxiliar Administrativo", "Contador", "Supervisor"});

        this.novo = new JButton("Novo");
        this.novo.addActionListener(this);
        this.salvar = new JButton("Salvar");
        this.salvar.addActionListener(this);
        this.excluir = new JButton("Excluir");
        this.excluir.addActionListener(this);


        this.panel = new JPanel(new MigLayout());
        this.panel.add(new JLabel("Nome"));
        this.panel.add(nome, "pushx, growx");

        this.panel.add(new JLabel("Idade"), "gap 10");
        this.panel.add(idade, "pushx, growx, wrap");

        this.panel.add(new JLabel("Departamento"));
        this.panel.add(departamento, "growx");
        this.panel.add(new JLabel("Cargo"), "gap 10");
        this.panel.add(cargo, "growx, wrap");

        this.panel.add(novo, "skip, split 3");
        this.panel.add(salvar);
        this.panel.add(excluir);

        this.setLayout(new BorderLayout());
        this.add(this.scrollPane, BorderLayout.CENTER);
        this.add(this.panel, BorderLayout.PAGE_END);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new TableModelTeste().setVisible(true);
            }
        });
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource().equals(novo)) {
            resetForm();
            nv = true;
        } else if (e.getSource().equals(salvar)) {
            try {
                if (nv) {
                    ((FuncionarioTableModel) tableFuncionario.getModel()).adicionar(new Funcionario(nome.getText(),
                            Integer.parseInt(idade.getText()), departamento.getSelectedItem().toString(), cargo.getSelectedItem().toString()));
                    resetForm();
                } else {
                    ((FuncionarioTableModel) tableFuncionario.getModel()).atualizar(tableFuncionario.getSelectedRow(), new Funcionario(nome.getText(),
                            Integer.parseInt(idade.getText()), departamento.getSelectedItem().toString(), cargo.getSelectedItem().toString()));
                    resetForm();
                }
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "Erro ao realizar operacao");
                ex.printStackTrace();
            }
        } else if (e.getSource().equals(excluir)) {
            try {
                ((FuncionarioTableModel) tableFuncionario.getModel()).excluir(tableFuncionario.getSelectedRow());
                resetForm();
            } catch (IndexOutOfBoundsException i) {
                JOptionPane.showMessageDialog(this, "Nenhum item selecionado");
            }
        }
    }

    private void resetForm() {
        this.nome.setText("");
        this.idade.setText("");
        this.departamento.setSelectedIndex(0);
        this.cargo.setSelectedIndex(0);
        nv = true;
    }

    private void listaMouseClick(MouseEvent evt) {
        nv = false;
        Funcionario f = ((FuncionarioTableModel) tableFuncionario.getModel()).getFuncionario(tableFuncionario.getSelectedRow());
        nome.setText(f.getNome());
        idade.setText(f.getIdade().toString());
        cargo.setSelectedItem(f.getCargo());
        departamento.setSelectedItem(f.getDepartamento());
    }
}

Provavelmente você deve ter notado algo novo: MigLayout.
MigLayout é uma framework que facilita a criação de interfaces gráficas através de simples configurações, economizando várias linhas de código e simplificando o entendimento. Para este exemplo, faça o download da API no site http://www.miglayout.com/.
Futuramente aprenderemos um pouco mais sobre esta framework.
Finalmente, observe atentamente os nossos 4 novos métodos em funcionamento. Estes são incomparavelmente mais simples e diretos do que quando se usa DefaultTableModel, isto derruba todas as suas dúvidas quanto a vantagem de se criar um TableModel.
No próximo post iremos continuar com nosso exemplo fazendo com que seja possível editar o item na própria célula da tabela.
Att.

terça-feira, 5 de junho de 2012

Crie o seu próprio TableModel

Pessoal...
Este é o meu primeiro post (aeee...). E vou logo começando com algo que percebo que causa muito nó na cabeça de alguns programadores: Por que não utiliza DefaultTableModel?
Aqui vai a resposta: o código fica confuso e mais difícil de manter; não representa o objeto em si, havendo a necessidade de duplicação de objetos (o objeto propriamente dito, e o que representará na lista); força com que seja apresentado o id (ou algo único que identifique o objeto) dentre vários outros que podemos citar.
Todo os problemas citados acima e até mesmo os que não me lembrei são solucionados quando implementamos nosso próprio TableModel.
Para este exemplo, vamos cria um table com informações de funcionários (nome, idade, departamento, cargo).

Primeiro vamos criar nossa classe Funcionario:

public class Funcionario {
    private String nome;
    private Integer idade;
    private String departamento;
    private String cargo;

    public Funcionario() {
    }

    public Funcionario(String nome, Integer idade, String departamento, String cargo) {
        this.nome = nome;
        this.idade = idade;
        this.departamento = departamento;
        this.cargo = cargo;
    }

    public String getCargo() {
        return cargo;
    }

    public void setCargo(String cargo) {
        this.cargo = cargo;
    }

    public String getDepartamento() {
        return departamento;
    }

    public void setDepartamento(String departamento) {
        this.departamento = departamento;
    }

    public Integer getIdade() {
        return idade;
    }

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

    public String getNome() {
        return nome;
    }

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

Vamos ao o que nos interessa de verdade:

import java.util.LinkedList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class FuncionarioTableModel extends AbstractTableModel {
    //nome da coluna da table
    private final String[] colunas = new String[]{"Nome", "Idade", "Departamento", "Cargo"};
    //lista para a manipulacao do objeto
    private List<Funcionario> listaFuncionario;

    public FuncionarioTableModel() {
        listaFuncionario = new LinkedList<Funcionario>();
    }

    public FuncionarioTableModel(List<Funcionario> listaFuncionario) {
        this.listaFuncionario = listaFuncionario;
    }
 
    //numero de linhas
    public int getRowCount() {
        return listaFuncionario.size();
    }

    //numero de colunas
    public int getColumnCount() {
        return colunas.length;
    }

    //define o que cada coluna conterá do objeto
    public Object getValueAt(int rowIndex, int columnIndex) {
        Funcionario f = listaFuncionario.get(rowIndex);
        switch(columnIndex){
            case 0:
                return f.getNome();
            case 1:
                return f.getIdade();
            case 2:
                return f.getDepartamento();
            case 3:
                return f.getCargo();
            default:
                return null;
        }
    }

    //determina o nome das colunas
    @Override
    public String getColumnName(int column) {
        return colunas[column];
    }

    //determina que tipo de objeto cada coluna irá suportar
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch(columnIndex){
        case 0:
            return String.class;
        case 1:
            return Integer.class;
        case 2:
            return String.class;
        case 3:
            return String.class;
        default:
            return null;
        }
    }
}

Os métodos descritos acima são os necessários para se criar um TableModel básico. Podemos criar também métodos para adicionar, excluir e editar itens diretamente do table (vamos aprimorar isto no próximo post). Observe que neste método, o modelo irá suportar o próprio objeto Funcionario, o que não iria acontecer seu fosse usado DefaultTableModel.

E para finalizar:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class TableModelTeste extends JFrame {

    private JTable tableFuncionario;
    private JScrollPane scrollPane;
 
    private List<Funcionario> listaFuncionarios;
 
    public TableModelTeste() {
        init();
    }

    final void init() {
        this.setTitle("Exemplo de TableModel");
        //populando a lista para inserir no table
        this.listaFuncionarios = new LinkedList<Funcionario>();
        this.listaFuncionarios.add(new Funcionario("Marlon Meneses", 26, "Centro Tecnologico", "Desenvolvedor"));
        this.listaFuncionarios.add(new Funcionario("Fulano Teste", 19, "Centro Tecnologico", "Estagiario"));
        this.listaFuncionarios.add(new Funcionario("Siclano Anonimo", 32, "Recepcao", "Auxiliar Administrativo"));
        this.listaFuncionarios.add(new Funcionario("Beltrano Nao Sei O Nome", 30, "Centro Tecnologico", "Gerente de Projetos"));
        //adicionando no table
        this.tableFuncionario = new JTable(new FuncionarioTableModel(this.listaFuncionarios));
        this.scrollPane = new JScrollPane(this.tableFuncionario);
     
        this.setLayout(new BorderLayout());
        this.add(this.scrollPane);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new TableModelTeste().setVisible(true);
            }
        });
    }
}

Pronto!
Pode até parecer, mas não é difícil.
No próximo post vamos aprimorar este exemplo.
Até a próxima