Button does not work when code is added to AbstractTableModel

2

I created a test project to implement in a larger project of a table with a button as one of the elements of the row. It works perfectly, but when I try to add to my code the button does not perform the action that was programmed. It is being done with AbstractTableModel. Anyone have an idea where the problem might be?

Testable design of what I need to do:

Table.java

public class Tabela extends JFrame{

    public Tabela(){
        super("Teste de Componentes na Coluna");

        Object[][] data = {
            {"1", "Azul", new Integer(2013), "21"},
            {"2", "Roxo", new Integer(2013), "1"},
            {"3", "Preto", new Integer(2013), "2"},
            {"4", "Vermelho", new Integer(2013), "8"},
            {"5", "Rosa", new Integer(2013), "70"},
            {"6", "Verde", new Integer(2013), "10"}
        };

        String columnHeaders[] = {"Position", "Color", "Last Year Won", "Trophies"};


        JTable table = new JTable(data,columnHeaders);

        table.getColumnModel().getColumn(1).setCellRenderer(new ButtonRenderer());
        table.getColumnModel().getColumn(1).setCellEditor(new ButtonEditor(new JTextField()));

        JScrollPane pane = new JScrollPane(table);
        getContentPane().add(pane);
        setSize(450,100);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Tabela t = new Tabela();
        t.setVisible(true);
    }

    class ButtonRenderer extends JButton implements TableCellRenderer{

        public ButtonRenderer(){
            setOpaque(true);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object obj, 
                boolean selected, boolean focused, int row, int col) {
            setText((obj == null) ? "":obj.toString());
            return this;
        }

    }

    class ButtonEditor extends DefaultCellEditor{
    protected JButton btn;
    private String lbl;
    private Boolean clicked;

    public ButtonEditor(JTextField txt){
        super(txt);
        btn = new JButton();
        btn.setOpaque(true);

        btn.addActionListener(new ActionListener(){
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        fireEditingStopped();
                    }
        });
    }

    public Component getTableCellEditorComponent(JTable table, Object obj, boolean selected, int row, int col){
        lbl = (obj == null) ? "":obj.toString();
        btn.setText(lbl);
        clicked = true;
        return btn;
    }

        public Object getCellEditorValue(){
    if(clicked){
        JOptionPane.showMessageDialog(btn, lbl + "Clicked");
    }
    clicked = false;
    return new String(lbl);
}

        public boolean stopCellEditing(){
                clicked = false;
                return super.stopCellEditing();
        }

        protected void fireEditingStopped(){
                super.fireEditingStopped();
        }
}

}

Project where the table should be added:

PendenciaView.java

public class PendenciaView extends JPanel {
    private JTextField txtId;

    PendenciaTableModel tableModel = new PendenciaTableModel();
    private final JTable table;

    /**
     * Create the panel.
     */
    public PendenciaView() {
        setLayout(null);
        setSize(794, 548);

        JLabel lblListaDePendencias = new JLabel("Lista de Pend\u00EAncias:");
        lblListaDePendencias.setBounds(10, 11, 120, 14);
        add(lblListaDePendencias);

        JLabel lblFiltrarPor = new JLabel("Filtrar por:");
        lblFiltrarPor.setBounds(10, 464, 60, 14);
        add(lblFiltrarPor);

        JLabel lblCategoria = new JLabel("Categoria:");
        lblCategoria.setBounds(89, 489, 60, 14);
        add(lblCategoria);

        JComboBox cmbCategoria = new JComboBox();
        cmbCategoria.setBounds(160, 486, 150, 20);
        cmbCategoria.addItem("Todas");
        cmbCategoria.addItem("Pedido");
        cmbCategoria.addItem("Produto");
        cmbCategoria.addItem("Categoria");
        cmbCategoria.addItem("Comprador");      
        add(cmbCategoria);

        JLabel lblDataDeInicio = new JLabel("Data de In\u00EDcio:");
        lblDataDeInicio.setBounds(327, 486, 90, 14);
        add(lblDataDeInicio);

        JDateChooser dcDataDeInicio = new JDateChooser();
        dcDataDeInicio.setBounds(427, 486, 130, 20);        
        add(dcDataDeInicio);
        dcDataDeInicio.setDateFormatString("dd/MM/yyyy");

        JLabel lblDataDeFim = new JLabel("Data de Fim:");
        lblDataDeFim.setBounds(567, 489, 77, 14);
        add(lblDataDeFim);

        JDateChooser dcDataDeFim = new JDateChooser();      
        dcDataDeFim.setBounds(654, 486, 130, 20);
        add(dcDataDeFim);
        dcDataDeFim.setDateFormatString("dd/MM/yyyy");

        JLabel lblId = new JLabel("ID:");
        lblId.setBounds(10, 489, 15, 14);
        add(lblId);

        txtId = new JTextField();
        txtId.setBounds(28, 486, 51, 20);
        add(txtId);
        txtId.setColumns(10);

        JButton btnFiltrar = new JButton("Filtrar");
        btnFiltrar.setBounds(695, 514, 89, 23);
        add(btnFiltrar);

        JPanel panel = new JPanel();
        panel.setBounds(10, 31, 774, 380);
        add(panel);
        panel.setLayout(null);

        table = new JTable(tableModel);
        table.setBounds(0, 0, 774, 380);
        panel.add(table);

        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setBounds(0, 0, 774, 380);
        panel.add(scrollPane);

        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);

        JButton btnRemoverPendencias = new JButton("Remover Pend\u00EAncias");
        btnRemoverPendencias.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                //Remove uma linha
                if(table.getSelectedRow() != -1){
                      tableModel.removeRow(table.getSelectedRow());
                }
            }
        });
        btnRemoverPendencias.setBounds(10, 422, 157, 23);
        add(btnRemoverPendencias);

        //"Selecionar", "ID", "Pendência", "Data e Hora", "Descrição", "Detalhes"
        table.getColumnModel().getColumn(0).setMaxWidth(70);
        table.getColumnModel().getColumn(1).setMaxWidth(50);
        table.getColumnModel().getColumn(2).setMaxWidth(180);
        table.getColumnModel().getColumn(3).setMaxWidth(100);
        table.getColumnModel().getColumn(4).setMaxWidth(300);
        table.getColumnModel().getColumn(5).setMaxWidth(80);

        PendenciaModel pm = new PendenciaModel();
        pm.setSelecionado(true);
        pm.setId(1);
        pm.setPendencia("BlaBlaBla");
        Date d = new Date();
        pm.setDataHora(d);
        pm.setDescricao("Erafoene vpanpvev np aevnrvpnaep");
        pm.setDetalhes("Abrir");

        tableModel.addRow(pm);

        PendenciaModel pm2 = new PendenciaModel();
        pm2.setSelecionado(true);
        pm2.setId(2);
        pm2.setPendencia("Vdioandd");
        Date d2 = new Date();
        pm2.setDataHora(d2);
        pm2.setDescricao("abdcdgae aefin aefioanfe aiefn");
        pm2.setDetalhes("Abrir");

        tableModel.addRow(pm2);

        Object[][] data = {
                {true, 1, "Azul", new Date(), "Bçlasncaio evwiwwe wavejh", "Abrir"},
                {true, 1, "Roxo", new Date(), "Bçlasncaio evwiwwe wavejh", "Abrir"},
                {true, 1, "Verde", new Date(), "Bçlasncaio evwiwwe wavejh", "Abrir"},
                {true, 1, "Rosa", new Date(), "Bçlasncaio evwiwwe wavejh", "Abrir"},
                {true, 1, "Branco", new Date(), "Bçlasncaio evwiwwe wavejh", "Abrir"},
            };


        table.getColumnModel().getColumn(5).setCellRenderer(new ButtonRenderer());
        table.getColumnModel().getColumn(5).setCellEditor(new ButtonEditor(new JTextField()));


    }

       class ButtonRenderer extends JButton implements TableCellRenderer{

            public ButtonRenderer(){
                setOpaque(true);
            }

            @Override
            public Component getTableCellRendererComponent(JTable table, Object obj, 
                    boolean selected, boolean focused, int row, int col) {
                setText((obj == null) ? "":obj.toString());
                return this;
            }

        }

        class ButtonEditor extends DefaultCellEditor{
        protected JButton btn;
        private String lbl;
        private Boolean clicked;

        public ButtonEditor(JTextField txt){
            super(txt);
            btn = new JButton();
            btn.setOpaque(true);

            btn.addActionListener(new ActionListener(){
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            fireEditingStopped();
                        }
            });
        }

        public Component getTableCellEditorComponent(JTable table, Object obj, boolean selected, int row, int col){
            lbl = (obj == null) ? "":obj.toString();
            btn.setText(lbl);
            clicked = true;
            return btn;
        }

            public Object getCellEditorValue(){
        if(clicked){
            JOptionPane.showMessageDialog(btn, lbl + "Clicked");
        }
        clicked = false;
        return new String(lbl);
    }

            public boolean stopCellEditing(){
                    clicked = false;
                    return super.stopCellEditing();
            }

            protected void fireEditingStopped(){
                    super.fireEditingStopped();
            }
    }


}

PendenceTableModel.java

public class PendenciaTableModel extends AbstractTableModel {


    private List<PendenciaModel> dados = new ArrayList<>();
    private String[] colunas = {"Selecionar", "ID", "Pendência", "Data e Hora", "Descrição", "Detalhes"};

    @Override
    public String getColumnName(int column){
        return colunas[column];
    }

    @Override
    public int getColumnCount() {
        return colunas.length;
    }

    @Override
    public int getRowCount() {
        return dados.size();
    }

    @Override
    public Object getValueAt(int linha, int coluna) {
        switch(coluna){
            case 0:
                return dados.get(linha).getSelecionado();
            case 1:
                return dados.get(linha).getId();
            case 2:
                return dados.get(linha).getPendencia();
            case 3:
                return dados.get(linha).getDataHora();
            case 4:
                return dados.get(linha).getDescricao();
            case 5:
                return dados.get(linha).getDetalhes();
        }

        return null;
    }

    public void addRow(PendenciaModel pm) {
        this.dados.add(pm);
        this.fireTableDataChanged();    
    }

    public void removeRow(int linha){
        this.dados.remove(linha);
        this.fireTableRowsDeleted(linha, linha);
    }



}

PendingModel.java

public class PendenciaModel { 
    private boolean selecionado;
    private int id;
    private String pendencia;
    private Date dataHora;
    private String descricao;
    private String detalhes;

    public boolean getSelecionado() {
        return selecionado;
    }
    public void setSelecionado(boolean selecionado) {
        this.selecionado = selecionado;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getPendencia() {
        return pendencia;
    }
    public void setPendencia(String pendencia) {
        this.pendencia = pendencia;
    }
    public Date getDataHora() {
        return dataHora;
    }
    public void setDataHora(Date dataHora) {
        this.dataHora = dataHora;
    }
    public String getDescricao() {
        return descricao;
    }
    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }
    public String getDetalhes() {
        return detalhes;
    }
    public void setDetalhes(String detalhes) {
        this.detalhes = detalhes;
    }


}
    
asked by anonymous 30.10.2018 / 17:31

2 answers

1

As you are doing, in addition to incorrectly using DefaultCellEditor , which expects JTextField and you are using JButton , you will also have difficulties later to retrieve the object from the button line.

I would like to propose a more robust solution, which does not need to use editors or rendering, created by the user camickr , where the class ButtonColumn adds a button in each column of the table automatically, you just have to set the action to be taken when there is a click.

To configure in your code, just copy the link class to your project and instantiate as below:

ButtonColumn buttonColumn = new ButtonColumn(table, action, columnIndex);

where table is your table, action is the action that the button will have and columnIndex is the index of the column where the button will be displayed.

For demonstration purposes, I created the action below that displays the line that was clicked:

Action mostrarDetalhes = new AbstractAction() {

    @Override
    public void actionPerformed(ActionEvent e) {
        //recupera a tabela
        JTable table = (JTable)e.getSource();
        //recupera a linha onde houve o clique
        int modelRow = Integer.valueOf(e.getActionCommand());
        JOptionPane.showMessageDialog(null, "Linha " + modelRow + " foi clicada");

    }
};

ButtonColumn buttonColumn = new ButtonColumn(table, mostrarDetalhes, 5);

The result of this example implemented in your code is:

Just by highlighting the class author's warning, the column needs to be editable, so you also need to apply the hint of Carlos's answer.

    
31.10.2018 / 12:23
1

Your template does not allow editing of data - documentation of method isCellEditable of AbstractTableModel :" Returns false. ", Ie no cell will be editable, its CellEditor will never be called , so the button will not be activated.

Solution, override the isCellEditable method to allow editing of its column:

public class PendenciaTableModel extends AbstractTableModel {

    ...

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return columnIndex == 5 || super.isCellEditable(rowIndex, columnIndex);
    }
}

Note:

  • Instead of directly using literals (example 5 ) to identify the columns, it is preferable to use constants private static final int COL_DETALHE = 5;

  • (obviously) the above solution is also valid to allow editing of other columns

  • 31.10.2018 / 10:04