Reputation: 23
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
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
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
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