Goose Looking
Goose Looking

Reputation: 23

Java Swing Add an Object to a Table

I am having difficulties to add an object to a table. My table has 4 column and the Object I am trying to add is created via user input. I am trying to add it to the table when the user clicks on the button "Validate". (i didn't post all my code it would be too long but you have the important part here)

final Object[] columnNames = {"Card type", "Account Number","Card Number", "Amount", "Select"};
final Cards[][] rows = new MyCards[columnNames.length][];
table = new JTable(rows, columnNames);

approve.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) {
                Cards newCard = new Cards();
                if(comboCardTypes.getSelectedItem().equals(Cards.CardType.DEBIT)){
                    newCard.setType(Cards.CardType.DEBIT);  

                }
                if(comboCardTypes.getSelectedItem().equals(Cards.CardType.CREDIT)){
                    newCard.setType(Cards.CardType.CREDIT);
                }
                newCard.setAccountNb(Integer.parseInt(answerTxt2.getText()));
                newCard.setCardNumber(Integer.parseInt(answerTxt3.getText()));
                newCard.setMoneyCurrent(Double.parseDouble(answerTxt4.getText()));
                table.add(newCard, index);


                index++;
            } 
        });

Upvotes: 1

Views: 1995

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

Using table = new JTable(rows, columnNames); constructs a DefaultTableModel behind the scenes.

DefaultTableModel manages individual rows and columns in an unstructured way, meaning that you will have to decompose any objects values and push them into the model and recompose any objects from the data you pull from the table.

This is counter productive, especially when you already have a object which contains the basic data you want to manage.

A better solution would be to define and use your own TableModel which was designed to manage the object itself.

For example...

public static class CardTableModel extends AbstractTableModel {

    protected static String[] COLUMN_NAMES = {"Card type", "Account Number","Card Number", "Amount", "Select"};
    protected static Class[] COLUMN_CLASSES = {String.class, Integer.class, Integer.class, Double.class, Boolean.class};        
    
    private Set<Integer> selected;
    private List<Card> cards;

    public CardTableModel() {
        cards = new ArrayList<>(25);
        selected = new TreeSet<Integer>();
    }
    
    @Override
    public int getRowCount() {
        return cards.size();
    }

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

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

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return COLUMN_CLASSES[columnIndex];
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return columnIndex == 4;
    }
    
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Card card = cards.get(rowIndex);
        switch (columnIndex) {
            case 0: return card.getCartType().toString();
            case 1: return card.getAccountNumber();
            case 2: return card.getCardNumber();
            case 3: return card.getAmmount();
            case 4: return selected.contains(rowIndex);
        }
        return null;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (columnIndex != 4) {
            return;
        }
        if (!(aValue instanceof Boolean)) {
            return;
        }
        boolean isSelected = (Boolean)aValue;
        if (isSelected) {
            selected.add(rowIndex);
        } else {
            selected.remove(rowIndex);
        }
        
        fireTableCellUpdated(rowIndex, columnIndex);
    }
    
    public void add(Card card) {
        int index = cards.size();
        cards.add(card);
        fireTableRowsInserted(index, index);
    }

    public Card cardAt(int rowIndex) {
        return cards.get(rowIndex);
    }
    
}

This then allows you maintain the Card information in a single place and reduces the risk of it coming out of sync as well as removing the need to "decode" and "encode" the data.

Have a look at How to use tables for more details

Runnable example...

This is a simple runnable example demonstrates the basic concepts of using the CardTableModel

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    private CardTableModel model;

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                model = new CardTableModel();
                JTable table = new JTable(model);

                JButton btn = new JButton("Add");
                btn.addActionListener(new ActionListener() {
                    private Random rnd = new Random();
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Card.CardType type;
                        int accountNumber = rnd.nextInt();
                        int cardNumnber = rnd.nextInt();
                        double amount = rnd.nextDouble();
                        if (rnd.nextBoolean()) {
                            type = Card.CardType.CREDIT;
                        } else {
                            type = Card.CardType.DEBIT;
                        }

                        Card card = new MyCard(type, accountNumber, cardNumnber, amount);
                        model.add(card);
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(table));
                frame.add(btn, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Card {
        public enum CardType {
            CREDIT, DEBIT;
        }

        public CardType getCardType();
        public int getAccountNumber();
        public int getCardNumber();
        public double getAmount();
    }

    public class MyCard implements Card {
        private CardType cardType;
        private int accountNumber;
        private int cardNumber;
        private double amount;

        public MyCard(CardType cardType, int accountNumber, int cardNumber, double amount) {
            this.cardType = cardType;
            this.accountNumber = accountNumber;
            this.cardNumber = cardNumber;
            this.amount = amount;
        }

        @Override
        public CardType getCardType() {
            return cardType;
        }

        public void setCardType(CardType cardType) {
            this.cardType = cardType;
        }

        @Override
        public int getAccountNumber() {
            return accountNumber;
        }

        public void setAccountNumber(int accountNumber) {
            this.accountNumber = accountNumber;
        }

        @Override
        public int getCardNumber() {
            return cardNumber;
        }

        public void setCardNumber(int cardNumber) {
            this.cardNumber = cardNumber;
        }

        @Override
        public double getAmount() {
            return amount;
        }

        public void setAmount(double amount) {
            this.amount = amount;
        }

    }

    public static class CardTableModel extends AbstractTableModel {

        protected static String[] COLUMN_NAMES = {"Card type", "Account Number", "Card Number", "Amount", "Select"};
        protected static Class[] COLUMN_CLASSES = {String.class, Integer.class, Integer.class, Double.class, Boolean.class};

        private Set<Integer> selected;
        private List<Card> cards;

        public CardTableModel() {
            cards = new ArrayList<>(25);
            selected = new TreeSet<Integer>();
        }

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

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

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

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return COLUMN_CLASSES[columnIndex];
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex == 4;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Card card = cards.get(rowIndex);
            switch (columnIndex) {
                case 0:
                    return card.getCardType().toString();
                case 1:
                    return card.getAccountNumber();
                case 2:
                    return card.getCardNumber();
                case 3:
                    return card.getAmount();
                case 4:
                    return selected.contains(rowIndex);
            }
            return null;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            if (columnIndex != 4) {
                return;
            }
            if (!(aValue instanceof Boolean)) {
                return;
            }
            boolean isSelected = (Boolean) aValue;
            if (isSelected) {
                selected.add(rowIndex);
            } else {
                selected.remove(rowIndex);
            }

            fireTableCellUpdated(rowIndex, columnIndex);
        }

        public void add(Card card) {
            int index = cards.size();
            cards.add(card);
            fireTableRowsInserted(index, index);
        }

        public Card cardAt(int rowIndex) {
            return cards.get(rowIndex);
        }

    }
}

Upvotes: 2

parsa
parsa

Reputation: 985

let's say you have the row and columns as bellow then the only thing you're missing is a TableModel. so the whole structure of adding to a JTable must be something like this

String[] columnNames = {"First Name",
        "Last Name",
        "Sport",
        "# of Years",
        "Vegetarian"};
Object[][] rowData = {
        {"Kathy", "Smith",
         "Snowboarding", new Integer(5), new Boolean(false)},
        {"John", "Doe",
         "Rowing", new Integer(3), new Boolean(true)},
        {"Sue", "Black",
         "Knitting", new Integer(2), new Boolean(false)},
        {"Jane", "White",
         "Speed reading", new Integer(20), new Boolean(true)},
        {"Joe", "Brown",
         "Pool", new Integer(10), new Boolean(false)}
    };
JTable table = new JTable();
TableModel dataModel = new AbstractTableModel() {
    public String getColumnName(int col) {
        return columnNames[col].toString();
    }
    public int getRowCount() { return rowData.length; }
    public int getColumnCount() { return columnNames.length; }
    public Object getValueAt(int row, int col) {
        return rowData[row][col];
    }
    public boolean isCellEditable(int row, int col)
        { return true; }
    public void setValueAt(Object value, int row, int col) {
        rowData[row][col] = value;
        fireTableCellUpdated(row, col);
    }
};
table.setModel(dataModel);

if you try this code planely you'll see that it works perfectly fine. but you only have to make it compatible to your code(since i don't have any idea about your code i couldn't use your code as an example)

Upvotes: 0

Related Questions