Why does resizing of JTable column generate garbage? - java

I'm currently implementing a program that uses a JTable to display some information. The table contains no more than 10 rows (so it's small).
While developing, I usually run the programs with the -verbose:gc option.
If I click on the line between 2 columns and keep moving it to the left, then to the right and so on, I notice that a lot of garbage is generated. The program does absolutely nothing while I'm doing this, so there is no other potential source of this garbage. Also, If I stop, the garbage collector also stops collecting.
If I keep resizing these columns for a minute or so, about 100MB+ of garbage is generated, which seems a lot.
This is not affecting how my program runs, but it just seems very weird. Why does it behave this way ?
EDIT
Here is an SSCCE:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class JTableTest
{
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
#Override public void run ()
{
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
frame.setLayout (null);
frame.setSize (700, 300);
frame.setResizable (false);
JTable table = new JTable ();
table.setAutoResizeMode (JTable.AUTO_RESIZE_ALL_COLUMNS);
String[] titles = { "Title 1", "Title 2", "Title 3", "Title 4", "Title 5" };
String[][] data = {
{ "Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3", "Row 1, Column 4", "Row 1, Column 5"},
{ "Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3", "Row 2, Column 4", "Row 2, Column 5"},
{ "Row 3, Column 1", "Row 3, Column 2", "Row 3, Column 3", "Row 3, Column 4", "Row 3, Column 5"},
{ "Row 4, Column 1", "Row 4, Column 2", "Row 4, Column 3", "Row 4, Column 4", "Row 4, Column 5"},
{ "Row 5, Column 1", "Row 5, Column 2", "Row 5, Column 3", "Row 5, Column 4", "Row 5, Column 5"}
};
table.setModel (new DefaultTableModel (data, titles)
{
#Override public boolean isCellEditable (int row, int column)
{
return false;
}
});
JScrollPane scrollpane = new JScrollPane (table);
scrollpane.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollpane.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollpane.setBounds (20, 20, 650, 250);
frame.add (scrollpane);
frame.setVisible (true);
}
});
}
}
Run the program with the -verbose:gc option. When running, click between "Title x" and "Title y" (x != y) and resize those columns. Keep the mouse clicked and keep moving it left and right. You'll see on stdout that the garbage collector is collecting garbage while you do this. (on my system it's doing this about 10 times / minute). If/when you stop, no more garbage is collected.

It generates garbage simply because it can. Java is a Garbage Collected language, essentially everything it does creates garbage.
While you are holding down and dragging that button, java is taking primitive activity (i.e. mouse button status, cursor position status, time, etc.) and creating events. It then compares that stream of events to things like old cursor position etc. to detect if the program actually wants to do anything with that information. When you do move it, Java needs to draw lines, file rectangles, draw text, etc.
All of those activity leave behind something, garbage, and eventually it needs to be collected.
Just sitting idle, your program is creating garbage, most likely very slowly, as internal timers and such die and are recycled. Try using the jconsole program to watch the heap and you'll see it creep up over time.
This is normal, and nothing to worry about. It's a feature, not a bug.

please
some changes in code
added JTextArea
do you confirm us that your output is the same as the output printed into JTextArea
(WinXP, Java6 --> looks like as forever)
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.DefaultCaret;
public class JTableTest {
private javax.swing.Timer timer = null;
private JTextArea text = new JTextArea();
public JTableTest() {
String[] titles = {"Title 1", "Title 2", "Title 3", "Title 4", "Title 5"};
String[][] data = {
{"Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3", "Row 1, Column 4", "Row 1, Column 5"},
{"Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3", "Row 2, Column 4", "Row 2, Column 5"},
{"Row 3, Column 1", "Row 3, Column 2", "Row 3, Column 3", "Row 3, Column 4", "Row 3, Column 5"},
{"Row 4, Column 1", "Row 4, Column 2", "Row 4, Column 3", "Row 4, Column 4", "Row 4, Column 5"},
{"Row 5, Column 1", "Row 5, Column 2", "Row 5, Column 3", "Row 5, Column 4", "Row 5, Column 5"}
};
JTable table = new JTable();
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
table.setModel(new DefaultTableModel(data, titles) {
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
});
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollpane = new JScrollPane(table);
scrollpane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollpane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
DefaultCaret caret = (DefaultCaret) text.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
JScrollPane scroll = new JScrollPane(text);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocation(150, 150);
frame.setSize(700, 300);
frame.setResizable(false);
frame.add(scrollpane, BorderLayout.NORTH);
frame.add(scroll, BorderLayout.CENTER);
frame.setVisible(true);
start();
}
private void start() {
timer = new javax.swing.Timer(1000, updateCol());
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
text.append("FreeMemory in Kb " + Runtime.getRuntime().freeMemory() / 1000 + "\n");
text.append("MaxMemory in Kb " + Runtime.getRuntime().maxMemory() / 1000 + "\n");
text.append("TotalMemory in Kb " + Runtime.getRuntime().totalMemory() / 1000 + "\n");
text.append("UsedMemory in Kb " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000) + "\n");
text.append("\n");
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JTableTest jTableTest = new JTableTest();
}
});
}
}
EDIT JTable and GC a few columns with 75k rows (82 -85Mb)
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
public class TriState extends JPanel {
private static final long K = 1024;
private static final long M = K * K;
private static final long G = M * K;
private static final long T = G * K;
protected static int ctr = 1;
private static final long serialVersionUID = 1L;
private JButton btnShow = new JButton("Show Form");
private JLabel lblMem = new JLabel();
private static final DecimalFormat df = new DecimalFormat("#,##0.#");
protected Timer updateTimer = new Timer();
public TriState() {
this.setLayout(new GridLayout());
add(btnShow);
add(lblMem);
updateTimer.scheduleAtFixedRate(new UpdateTimerTask(), 1000, 1000);
btnShow.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FrmReferrals fr = new FrmReferrals();
fr.setVisible(true);
}
});
}
class UpdateTimerTask extends TimerTask {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
dumpMemoryUsage();
}
});
}
}
protected void dumpMemoryUsage() {
System.gc();
Long t = Runtime.getRuntime().totalMemory();
long f = Runtime.getRuntime().freeMemory();
String st = convertToStringRepresentation(t);
String sf = convertToStringRepresentation(f);
String su = convertToStringRepresentation(t - f);
System.out.println("Total:" + st + "(" + t + ") Free:" + sf + "(" + f + ") Used:" + su + "(" + (t - f) + ")");
lblMem.setText(su + "/" + st);
}
public static String convertToStringRepresentation(final long value) {
final long[] dividers = new long[]{T, G, M, K, 1};
final String[] units = new String[]{"TB", "GB", "MB", "KB", "B"};
if (value < 1) {
throw new IllegalArgumentException("Invalid file size: " + value);
}
String result = null;
for (int i = 0; i < dividers.length; i++) {
final long divider = dividers[i];
if (value >= divider) {
final double dr = divider > 1 ? (double) value / (double) divider : (double) value;
result = df.format(dr) + units[i];
break;
}
}
return result;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the content pane.
TriState newContentPane = new TriState();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
protected class PopupMenu extends JPopupMenu {
public PopupMenu() {
JRadioButtonMenuItem item1 = new JRadioButtonMenuItem(new AbstractAction("Insert Item") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
item1.setActionCommand("Insert");
add(item1);
JRadioButtonMenuItem item2 = new JRadioButtonMenuItem(new AbstractAction("Delete Item") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
item2.setActionCommand("Delete");
add(item2);
}
}
public class FrmReferrals extends JFrame {
public FrmReferrals() {
super();
init();
}
protected void init() {
jbInit();
}
protected void closeIt() {
uninit();
}
// variables here
final Dimension dimPreferred = new Dimension(1270, 995);
final JTabbedPane tabbedPane = new JTabbedPane();
private JTable tblReferrals = null;
private PopupMenu popMenu = new PopupMenu();
protected void jbInit() {
setPreferredSize(dimPreferred);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setTitle("Referrals");
JPanel pnl = new JPanel();
pnl.setOpaque(false);
pnl.setLayout(new BorderLayout());
pnl.add(tabbedPane, BorderLayout.CENTER);
// put it all in the frame
add(pnl);
pack();
setLocationRelativeTo(null);
// init the table and model
ReferralsTableModel ctm = new ReferralsTableModel(buildDummyVector());
tblReferrals = new JTable(ctm);
tblReferrals.setComponentPopupMenu(popMenu);
tblReferrals.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tabbedPane.add(new JScrollPane(tblReferrals, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
addWindowListener(new WindowListener() {
#Override
public void windowActivated(WindowEvent e) {
}
#Override
public void windowClosed(WindowEvent e) {
}
#Override
public void windowClosing(WindowEvent e) {
closeIt();
}
#Override
public void windowDeactivated(WindowEvent e) {
}
#Override
public void windowDeiconified(WindowEvent e) {
}
#Override
public void windowIconified(WindowEvent e) {
}
#Override
public void windowOpened(WindowEvent e) {
}
});
}
protected Vector<DBO_Referrals> buildDummyVector() {
Vector<DBO_Referrals> vr = new Vector<DBO_Referrals>();
for (int x = 0; x < 75000; x++) {
DBO_Referrals r = new DBO_Referrals(x + (5000 * ctr));
vr.add(r);
}
return vr;
}
protected void uninit() {
tblReferrals.setComponentPopupMenu(null);
for (Component c : popMenu.getComponents()) {
PropertyChangeListener[] pl = c.getPropertyChangeListeners();
for (PropertyChangeListener l : pl) {
c.removePropertyChangeListener(l);
}
if (c instanceof JMenuItem) {
ActionListener[] al = ((JMenuItem) c).getActionListeners();
for (ActionListener l : al) {
((JMenuItem) c).removeActionListener(l);
}
}
}
popMenu = null;
}
protected class DBO_Referrals {
private long id;
private String Employee;
private String Rep;
private String Asst;
private String Client;
private String Dates;
private String Status;
private String Home;
public DBO_Referrals(long id) {
this.id = id;
Employee = "Employee" + id;
Rep = "Rep" + id;
Asst = "Asst" + id;
Client = "Client" + id;
Dates = "Dates" + id;
Status = "Status" + id;
Home = "Home" + id;
}
public long getId() {
return id;
}
public String getEmployee() {
return Employee;
}
public String getRep() {
return Rep;
}
public String getAsst() {
return Asst;
}
public String getClient() {
return Client;
}
public String getDates() {
return Dates;
}
public String getStatus() {
return Status;
}
public String getHome() {
return Home;
}
}
public class ReferralsTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector<DBO_Referrals> data = new Vector<DBO_Referrals>();
final String[] sColumns = {"id", "Employee", "Rep", "Assistant", "Client", "Date", "Status", "Home", "R"};
public ReferralsTableModel() {
super();
}
public ReferralsTableModel(Vector<DBO_Referrals> data) {
this();
this.data = data;
}
#SuppressWarnings("unchecked")
#Override
public Class<?> getColumnClass(int col) {
switch (col) {
case 0:
return Long.class;
default:
return String.class;
}
}
#Override
public int getColumnCount() {
return sColumns.length;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
if (row > data.size()) {
return null;
}
DBO_Referrals a = data.get(row);
switch (col) {
case 0:
return a.getId();
case 1:
return a.getEmployee();
case 2:
return a.getRep();
case 3:
return a.getAsst();
case 4:
return a.getClient();
case 5:
return a.getDates();
case 6:
return a.getStatus();
case 7:
return a.getHome();
case 8:
return "+";
default:
return null;
}
}
}
}
}

Related

JTable with different JCombobox for each line

I have a table that I'm loading with rows at run time. Once loaded the user needs to choose an item from a JComboBox in the first column for each line. Then he needs to chose an item from another JComboBoxon the same line in every rows. The content of the second JComboBox depends on the selection of the first JComboBox.
The way I coded it now is changing the combobox content for the whole second column.
columnProfile.setCellEditor(new DefaultCellEditor(comboBoxProf))
Is there a way to have a combobox object different on every row so I can work on it everytime I select a value in the first combobox?
The number of rows is not fixed until the user hits submit. He can add and delete rows.
I've used the basic Table example from Oracle and made the changes to reflect what I'm currently doing
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
public class TableRenderDemo extends JPanel {
private boolean DEBUG = false;
JComboBox comboBox2;
JComboBox comboBox1;
public TableRenderDemo() {
super(new GridLayout(1,0));
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
initColumnSizes(table);
setUpSportColumn(table, table.getColumnModel().getColumn(2));
setUpYearsColumn(table, table.getColumnModel().getColumn(3));
add(scrollPane);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getColumn() == 2){
comboBox2.removeAllItems();
/*REFILL COMBOBOX WITH WHAT I NEED FOR THIS ROW ONLY*/
}
}
});
}
private void initColumnSizes(JTable table) {
MyTableModel model = (MyTableModel)table.getModel();
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
TableCellRenderer headerRenderer =
table.getTableHeader().getDefaultRenderer();
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(
null, column.getHeaderValue(),
false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).
getTableCellRendererComponent(
table, longValues[i],
false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
if (DEBUG) {
System.out.println("Initializing width of column "
+ i + ". "
+ "headerWidth = " + headerWidth
+ "; cellWidth = " + cellWidth);
}
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
}
public void setUpSportColumn(JTable table,
TableColumn sportColumn) {
//Set up the editor for the sport cells.
comboBox1 = new JComboBox();
comboBox1.addItem("Snowboarding");
comboBox1.addItem("Rowing");
comboBox1.addItem("Knitting");
comboBox1.addItem("Speed reading");
comboBox1.addItem("Pool");
comboBox1.addItem("None of the above");
sportColumn.setCellEditor(new DefaultCellEditor(comboBox1));
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
}
public void setUpYearsColumn(JTable table,
TableColumn yearColumn) {
comboBox2 = new JComboBox();
comboBox2.addItem("1");
comboBox2.addItem("2");
comboBox2.addItem("3");
comboBox2.addItem("4");
comboBox2.addItem("5");
comboBox2.addItem("6");
yearColumn.setCellEditor(new DefaultCellEditor(comboBox2));
//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
yearColumn.setCellRenderer(renderer);
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
private Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", "1", new Boolean(false)},
{"John", "Doe",
"Rowing", "1", new Boolean(true)},
{"Sue", "Black",
"Knitting", "1", new Boolean(false)},
{"Jane", "White",
"Speed reading", "1", new Boolean(true)},
{"Joe", "Brown",
"Pool", "1", new Boolean(false)}
};
public final Object[] longValues = {"Jane", "Kathy",
"None of the above",
new Integer(20), Boolean.TRUE};
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value
+ " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TableRenderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableRenderDemo newContentPane = new TableRenderDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Say you had your data held in a Map<String, List<String>> with the Map's keys representing the values held by the first JComboBox, and the Map's values representing the changing values held by the 2nd column's JComboBox (the data does not need to be set up this way, but it's easy for MCVE/demonstration purposes), and call this map dataMap, then your column editor could look something like:
column1.setCellEditor(new DefaultCellEditor(combo1) {
#SuppressWarnings("unchecked")
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
// the items that will fill our JComboBox. Initially its empty
Object[] items = new Object[]{};
// get the value in the column to the left
Object column0Value = table.getValueAt(row, column - 1);
if (column0Value != null) {
// if the value is not null, then get the map's values
// and use it to fill our items array
items = dataMap.get(column0Value).toArray();
}
// get the super component, the JComboBox that is being used
// as an editor:
JComboBox<Object> superCombo = (JComboBox<Object>) super.getTableCellEditorComponent(table, value, isSelected,
row, column);
// create a model and fill with items
DefaultComboBoxModel<Object> comboModel = new DefaultComboBoxModel<>(items);
// set the cell editor's model and return
superCombo.setModel(comboModel);
return superCombo;
}
});
For example please check this MCVE as an example that uses the above cell editor and as an example of a MCVE that would work well in your future questions
import java.awt.Component;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
#SuppressWarnings("serial")
public class TableWithMultCombos extends JPanel {
private static final String[] COLUMN_NAMES = { "Day of Week", "Number" };
private Map<String, List<String>> dataMap = new LinkedHashMap<>();
private DefaultTableModel tblModel = new DefaultTableModel(COLUMN_NAMES, 5);
private JTable table = new JTable(tblModel);
private DefaultComboBoxModel<Object> combo2Model = new DefaultComboBoxModel<>();
private JComboBox<Object> combo0 = null;
private JComboBox<Object> combo1 = new JComboBox<>(combo2Model);
public TableWithMultCombos() {
dataMap.put("Monday", Arrays.asList(new String[] { "Mon - 1", "Mon - 2", "Mon - 3", "Mon - 4" }));
dataMap.put("Tuesday", Arrays.asList(new String[] { "Tues - 1", "Tues - 2", "Tues - 3", "Tues - 4" }));
dataMap.put("Wednesday", Arrays.asList(new String[] { "Wed - 1", "Wed - 2", "Wed - 3", "Wed - 4" }));
dataMap.put("Thursday", Arrays.asList(new String[] { "Thurs - 1", "Thurs - 2", "Thurs - 3", "Thurs - 4" }));
dataMap.put("Friday", Arrays.asList(new String[] { "Fri - 1", "Fri - 2", "Fri - 3", "Fri - 4" }));
combo0 = new JComboBox<>(dataMap.keySet().toArray());
TableColumn column0 = table.getColumnModel().getColumn(0);
column0.setCellEditor(new DefaultCellEditor(combo0));
TableColumn column1 = table.getColumnModel().getColumn(1);
column1.setCellEditor(new DefaultCellEditor(combo1) {
#SuppressWarnings("unchecked")
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
// the items that will fill our JComboBox. Initially its empty
Object[] items = new Object[]{};
// get the value in the column to the left
Object column0Value = table.getValueAt(row, column - 1);
if (column0Value != null) {
// if the value is not null, then get the map's values
// and use it to fill our items array
items = dataMap.get(column0Value).toArray();
}
// get the super component, the JComboBox that is being used
// as an editor:
JComboBox<Object> superCombo = (JComboBox<Object>) super.getTableCellEditorComponent(table, value, isSelected,
row, column);
// create a model and fill with items
DefaultComboBoxModel<Object> comboModel = new DefaultComboBoxModel<>(items);
// set the cell editor's model and return
superCombo.setModel(comboModel);
return superCombo;
}
});
table.setFillsViewportHeight(true);
add(new JScrollPane(table));
}
private static void createAndShowGui() {
TableWithMultCombos mainPanel = new TableWithMultCombos();
JFrame frame = new JFrame("TableWithMultCombos");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Getting a value back from an array using a random method

I am having issues with getting a correct value from my random method I am using. Everything else in my code works, but when I hit the random message button, I get an output on null null null null null instead of a random value from each array. My code is below. Any help to solve this would be greatly appreciated.
package shoutbox;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
public class ShoutBox {
String subj, obj, verB, adJ, adV, cannedM, randomM, tempSubj, tempObj, tempAdj, tempVerb, tempAdverb;
private final String[] stringItems = {
"I was sent here by the king to slay you!",
"I will leave you to your slumber.",
"I heard you have a piece of treasure I am interested in.",
"I heard you know a way to save princess Layla from illness.",
"Might I say you look lovely in the moonight.",
"I love dragons!",
"I will slay you and take your treasure!",
"Are you a luck dragon?",
"I think I will turn around and go home now.",
"Go ahead and try to roast me with your fire! I am a wizard, I will prevail!"
};
private final String[] subject = {
"I", "You", "Everyone", "They", "The King", "The Queen", "My Brother",
"We", "The gold", "The book"
};
private final String[] object = {
"sword", "treasure", "dragon", "cave", "head", "friends", "fire",
"blood", "jewels", "magic"
};
private final String[] verb = {
"yells", "hits", "torches", "sings", "laughs", "loves", "dances",
"scouts", "hates", "wants"
};
private final String[] adjective = {
"beautiful", "outragious", "pretty", "scary", "lazy", "heavy", "enormous",
"hot", "scaly", "scary"
};
private final String[] adverb = {
"quickly", "slowly", "softly", "skillfully", "wickedly", "underground", "tomorrow",
"uneasily", "quickly", "abruptly"
};
public void setSubject(String tempSubj) {
tempSubj = subj;
}
public void setObject(String tempObj) {
tempObj = obj;
}
public void setVerb(String tempVerb) {
tempVerb = verB;
}
public void setAdjective(String tempAdj) {
tempAdj = adJ;
}
public void setAdverb(String tempAdverb) {
tempAdverb = adV;
}
public String getSubject() {
Random genSub = new Random();
int randomSub = genSub.nextInt(subject.length);
subj = subject[randomSub];
return subj;
}
public String getObject() {
Random genOb = new Random();
int randomOb = genOb.nextInt(object.length);
obj = object[randomOb];
return obj;
}
public String getVerb() {
Random genVerb = new Random();
int randomVerb = genVerb.nextInt(verb.length);
verB = subject[randomVerb];
return verB;
}
public String getAdjective() {
Random genAd = new Random();
int randomAd = genAd.nextInt(adjective.length);
adJ = adjective[randomAd];
return adJ;
}
public String getAdverb() {
Random genAdverb = new Random();
int randomAdverb = genAdverb.nextInt(adverb.length);
adV = subject[randomAdverb];
return adV;
}
public ShoutBox() {
JFrame frame = new JFrame(); //setting up Jframe components
// Setting width, height, and title of window
frame.setTitle("Shout Box");
frame.setSize(450, 400); // Size of frame window
frame.setLocation(360, 200); // Start location of frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false); // So you cannot resize frame
JButton submitButton = new JButton("Submit");
JButton randomButton = new JButton("Random Message");
JLabel label = new JLabel("Pick a message and click submit or click random message");
JList JlistMap;
JTextArea textArearesult = new JTextArea(2, 21);
textArearesult.setEditable(false);
textArearesult.setLineWrap(true);
textArearesult.setWrapStyleWord(true);
JPanel panel = new JPanel();
JLabel label1 = new JLabel("");
label1.setForeground(Color.blue);
JLabel label2 = new JLabel(" Your Message you have chosen is: ");
label2.setForeground(Color.red);
JlistMap = new JList(stringItems);
JlistMap.setVisibleRowCount(10);
JlistMap.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//add(new JScrollPane(JlistMap)); //Not working as of now
panel.setBackground(Color.PINK); // Pink background color
frame.add(panel);
panel.add(label);
panel.add(JlistMap);
panel.add(submitButton);
panel.add(randomButton);
panel.add(label2);
panel.add(textArearesult);
// Action Listener for the submit button to get the message that will display in the JTextArea
submitButton.addActionListener((ActionEvent e) -> {
textArearesult.setText(ShoutOutCannedMessage()); //using ShoutOutCannedMessage method to return cannedM
});
randomButton.addActionListener((ActionEvent e) -> {
textArearesult.setText(ShoutOutRandomMessage()); //using ShoutOutCannedMessage method to return cannedM
});
// JList will get the selected Item and set the item to a string value t that will be set to cannedM
JlistMap.addListSelectionListener((ListSelectionEvent e) -> {
JList list = (JList) e.getSource();
String t = list.getSelectedValue().toString();
cannedM = t;
});
frame.setVisible(true); //set to be visible on panel
}
public String ShoutOutCannedMessage() {
return cannedM;
}
public String ShoutOutRandomMessage() {
randomM = tempSubj + " " + tempObj + " " + tempVerb + " " + tempAdj + " " + tempAdverb + ".";
return randomM;
}
}
package shoutbox;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
public class ShoutBox {
String cannedM, randomM, subJ, tempSubj, tempObj, tempAdj, tempVerb, tempAdverb;
private final String[] stringItems = {
"I was sent here by the king to slay you!",
"I will leave you to your slumber.",
"I heard you have a piece of treasure I am interested in.",
"I heard you know a way to save princess Layla from illness.",
"Might I say you look lovely in the moonight.",
"I love dragons!",
"I will slay you and take your treasure!",
"Are you a luck dragon?",
"I think I will turn around and go home now.",
"Go ahead and try to roast me with your fire! I am a wizard, I will prevail!"
};
private final String[] subject = {
"I", "You", "Everyone", "They", "The King", "The Queen", "My Brother",
"We", "The gold", "The book"
};
private final String[] object = {
"sword", "treasure", "dragon", "cave", "head", "friends", "fire",
"blood", "jewels", "magic"
};
private final String[] verb = {
"yells", "hits", "torches", "sings", "laughs", "loves", "dances",
"scouts", "hates", "wants"
};
private final String[] adjective = {
"beautiful", "outragious", "pretty", "scary", "lazy", "heavy", "enormous",
"hot", "scaly", "scary"
};
private final String[] adverb = {
"quickly", "slowly", "softly", "skillfully", "wickedly", "underground", "tomorrow",
"uneasily", "quickly", "abruptly"
};
public void setSubject() {
Random genSub = new Random();
int randomSub = genSub.nextInt(subject.length);
tempSubj = subject[randomSub];
}
public void setObject() {
Random genOb = new Random();
int randomOb = genOb.nextInt(object.length);
tempObj = object[randomOb];
}
public void setVerb() {
Random genVerb = new Random();
int randomVerb = genVerb.nextInt(verb.length);
tempVerb = verb[randomVerb];
}
public void setAdjective() {
Random genAd = new Random();
int randomAd = genAd.nextInt(adjective.length);
tempAdj = adjective[randomAd];
}
public void setAdverb() {
Random genAdverb = new Random();
int randomAdverb = genAdverb.nextInt(adverb.length);
tempAdverb = subject[randomAdverb];
}
public String getSubject() {
return tempSubj;
}
public String getObject() {
return tempObj;
}
public String getVerb() {
return tempVerb;
}
public String getAdjective() {
return tempAdj;
}
public String getAdverb() {
return tempAdverb;
}
public ShoutBox() {
JFrame frame = new JFrame(); //setting up Jframe components
// Setting width, height, and title of window
frame.setTitle("Shout Box");
frame.setSize(450, 400); // Size of frame window
frame.setLocation(360, 200); // Start location of frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false); // So you cannot resize frame
JButton submitButton = new JButton("Submit");
JButton randomButton = new JButton("Random Message");
JLabel label = new JLabel("Pick a message and click submit or click random message");
JList JlistMap;
JTextArea textArearesult = new JTextArea(1, 30);
textArearesult.setEditable(false);
textArearesult.setLineWrap(true);
textArearesult.setWrapStyleWord(true);
JPanel panel = new JPanel();
JLabel label1 = new JLabel("");
label1.setForeground(Color.blue);
JLabel label2 = new JLabel(" Your Message you have chosen is: ");
label2.setForeground(Color.red);
JlistMap = new JList(stringItems);
JlistMap.setVisibleRowCount(10);
JlistMap.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//add(new JScrollPane(JlistMap)); //Not working as of now
panel.setBackground(Color.PINK); // Pink background color
frame.add(panel);
panel.add(label);
panel.add(JlistMap);
panel.add(submitButton);
panel.add(randomButton);
panel.add(label2);
panel.add(textArearesult);
// Action Listener for the submit button to get the message that will display in the JTextArea
submitButton.addActionListener((ActionEvent e) -> {
textArearesult.setText(ShoutOutCannedMessage()); //using ShoutOutCannedMessage method to return cannedM
});
randomButton.addActionListener((ActionEvent e) -> {
textArearesult.setText(ShoutOutRandomMessage()); //using ShoutOutCannedMessage method to return cannedM
});
// JList will get the selected Item and set the item to a string value t that will be set to cannedM
JlistMap.addListSelectionListener((ListSelectionEvent e) -> {
JList list = (JList) e.getSource();
String t = list.getSelectedValue().toString();
cannedM = t;
});
frame.setVisible(true); //set to be visible on panel
}
public String ShoutOutCannedMessage() {
return cannedM;
}
public String ShoutOutRandomMessage() {
randomM = getSubject() + " " + getObject() + " " + getVerb() + " " + getAdjective() + " " + getAdverb() + ".";
return randomM;
}
}
You have to set the values of your attributes tempSubj, tempObj, tempVerb, tempAdjand tempAdverb.
Notice that you've declare these attributes but you haven't affect them with any value. Therefore, they assume the value null.
In order to fix this, you have set them with some value explicitly or invoke their setters, which you've already created. Also you've to fix your setters because they're not properly setting your attributes:
public void setSubject(String subj) {
tempSubj = subj;
}
public void setObject(String obj) {
tempObj = obj;
}
public void setVerb(String verb) {
tempVerb = verb;
}
public void setAdjective(String adj) {
tempAdj = adj;
}
public void setAdverb(String adv) {
tempAdverb = adv;
}
EDIT
Other approach, is to use your getters, where you have the random code logic:
public String ShoutOutRandomMessage() {
randomM = getSubject() + " " + getObject() + " " + getVerb() + " " + getAdjective() + " " + getAdverb() + ".";
return randomM;
}

Modify the instancer object into instanced object

I have an object A that instance another object B.
I was wondering whether or not is possible to modify A with instructions in B.
In my circumstance, I have a Timetable (its code is under "Object A") that open (by InsertLesson.setVisible(true);) a Window to let the user compile its cells with lesson. At this time, the Window (InsertLesson, code under "object B") get the lesson selection by user but it is not able to write in the table that selection. How can I do?
Here the code
Object A:
public class TablePanel extends JPanel
{
private JTable table;
public Tabella()
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
table = new JTable(new MyTableModel());
table.setFillsViewportHeight(true);
table.setPreferredScrollableViewportSize(new Dimension(500, 100));
JScrollPane jps = new JScrollPane(table);
add(jps);
add(new JScrollPane(table));
table.setCellSelectionEnabled(true);
table.addMouseListener(
new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
int row = table.rowAtPoint(new Point(e.getX(), e.getY()));
int col = table.columnAtPoint(new Point(e.getX(), e.getY()));
if (col>0) {
if (e.getClickCount() > 1) {
if (row == 5 | row == 6)
{
JOptionPane.showMessageDialog(null, "Impossible to set lesson.");
return;
}
else {
table.getColumnName(col);
String day = table.getColumnName(col);
String hour = (String) table.getValueAt(row, 0);
InsertLesson cell = new InsertLesson(day, hour);
cel.setVisible(true);
}
}
}
}
}
);
}
private class MyTableModel extends AbstractTableModel {
private String[] columns = {"","Monday","Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
private String[][] data = {{"8:30 - 9:30","","","","","",""},
{"9:30 - 10:30","","","","","",""},
{"10:30 - 11:30","","","","","",""},
{"11:30 - 12:30","","","","","",""},
{"12:30 - 13:30","","","","","",""},
{"13:30 - 14:30","","","","","",""},
{"14:30 - 15:30","","","","","",""},
{"15:30 - 16:30","","","","","",""},
{"16:30 - 17:30","","","","","",""}};
public int getColumnCount() {
return columns.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columns[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
}
Object B (which has to modify A):
public InsertLesson (String day, String hour)
{
initialize(day, hour);
}
private void initialize(String day, String hour) {
this.setSize(600,200);
this.setTitle("Insert Lesson");
this.setLocationRelativeTo(null);
String[] lessons = {"math", "english", "art"};
String [] classrooms = {"class1", "class2"};
JPanel centralPnl = new JPanel();
this.getContentPane().add(centralPnl, BorderLayout.CENTER);
final JComboBox classBox = new JComboBox(classrooms );
centralPnl.add(classBox);
final JComboBox lessonsBox = new JComboBox(lessons);
centralPnl.add(lessonsBox);
JPanel southPnl = new JPanel();
this.getContentPane().add(southPnl, BorderLayout.SOUTH);
JButton insLessonBtn = new JButton("Insert Lesson");
southPnl.add(insLessonBtn);
lessonsBox.addItemListener(new ItemListener()
{
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED)
{
selectedLesson = lessonsBox.getSelectedItem().toString();
}
}
});
classBox.addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED)
{
selectedClass = classBox.getSelectedItem().toString();
}
}
});
class MouseSpy implements MouseListener
{
public void mouseClicked(MouseEvent e)
{
JOptionPane.showMessageDialog(null,"Do something for modify table with\n"
+ "values of selectedLesson and selectedClass");
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
MouseListener listener = new MouseSpy();
insLessonBtn.addMouseListener(listener);
}
}
}
To update the table in A, B must invoke the method setValueAt() on the TableModel of A. Alternatively, add a method to your TableModel that does the update. A typical implementation of setValueAt() is seen here. If that doesn't help, please edit your question to include an sscce that exhibits the problem you encounter.
Addendum: I want to update the table … after the user press the … button.
As a concrete example using your TableModel, the Update button below updates the table's model with each press. Compare the implmentation of setValueAt () to the one cited above. The button's actionPerformed() method accesses a final reference to the TableModel in the enclosing scope, but you can pass a reference to your TableModel as a parameter to the constructor of InsertLesson.
Addendum: Would you write [it for] me?
No, but I will outline the approach, assuming a class InsertLesson,
TableModel model = new MyTableModel();
JTable table = new JTable(model);
InsertLesson cell = new InsertLesson(day, hour, model);
…
class InsertLesson {
TableModel model;
public InsertLesson(String day, String hour, TableModel model) {
this.model = model;
…
}
…
}
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
/**
* #see http://stackoverflow.com/a/18764073/230513
*/
public class Test {
private static class MyTableModel extends AbstractTableModel {
private String[] columns = {
"Time", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
private String[][] data = {
{"8:30 - 9:30", "", "", "", "", ""},
{"9:30 - 10:30", "", "", "", "", ""},
{"10:30 - 11:30", "", "", "", "", ""},
{"11:30 - 12:30", "", "", "", "", ""},
{"12:30 - 13:30", "", "", "", "", ""},
{"13:30 - 14:30", "", "", "", "", ""},
{"14:30 - 15:30", "", "", "", "", ""},
{"15:30 - 16:30", "", "", "", "", ""},
{"16:30 - 17:30", "", "", "", "", ""}};
#Override
public int getColumnCount() {
return columns.length;
}
#Override
public int getRowCount() {
return data.length;
}
#Override
public String getColumnName(int col) {
return columns[col];
}
#Override
public Object getValueAt(int row, int col) {
return data[row][col];
}
#Override
public void setValueAt(Object aValue, int row, int col) {
data[row][col] = (String) aValue;
fireTableCellUpdated(row, col);
}
}
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final TableModel model = new MyTableModel();
f.add(new JScrollPane(new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(600, 128);
}
}));
f.add(new JButton(new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
model.setValueAt(String.valueOf(e.getWhen() % 1000000), 1, 1);
}
}), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}

get latest value from jtable cell in java

Can someone give an example of question below:
I have a jtable like below
plus | minus | total
10 | 0 | 10
0 | 2 | 8
0 | 3 | 5
How can I get the value of latest total(5) so I can use it again in formula
total=total+plus-minus? Also the value of total will keep updated because of plus and minus will be added continuously.
Can someone give an example of question below:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Random;
import java.util.concurrent.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.DefaultTableModel;
public class ChangeNotifiersOnEvent extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private boolean runProcess = true;
private Random random = new Random();
private javax.swing.Timer timerRun;
private Executor executor = Executors.newCachedThreadPool();
private String[] columnNames = {"Source", "Hit", "Last", "Ur_Diff"};
private JTable table;
private Object[][] data = {{"Swing Timer", 2.99, 5, 1.01},
{"Swing Worker", 7.10, 5, 1.010}, {"TableModelListener", 25.05, 5, 1.01}};
private DefaultTableModel model = new DefaultTableModel(data, columnNames);
public ChangeNotifiersOnEvent() {
table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent tme) {
if (tme.getType() == TableModelEvent.UPDATE) {
if (tme.getColumn() == 1 && tme.getLastRow() == 2) {
double dbl = ((Double) table.getModel().getValueAt(2, 1))
- ((Integer) table.getModel().getValueAt(2, 2));
table.getModel().setValueAt(dbl, 2, 3);
} else if (tme.getColumn() == 1 && tme.getLastRow() == 0) {
prepareUpdateTableCell();
} else if (tme.getColumn() == 1 && tme.getLastRow() == 1) {
executor.execute(new MyTask(MyTask.UPDATE_TABLE_COLUMN));
}
}
}
});
table.setRowHeight(30);
table.setFont(new Font("Serif", Font.BOLD, 20));
table.getColumnModel().getColumn(0).setPreferredWidth(180);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
new Thread(this).start();
}
private void prepareUpdateTableCell() {
timerRun = new javax.swing.Timer(10, UpdateTableCell());
timerRun.setRepeats(false);
timerRun.start();
}
private Action UpdateTableCell() {
return new AbstractAction("Update Table Cell") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
double dbl = ((Double) table.getModel().getValueAt(0, 1))
- ((Integer) table.getModel().getValueAt(0, 2));
table.getModel().setValueAt(dbl, 0, 3);
}
};
}
#Override
public void run() {
while (runProcess) {
try {
Thread.sleep(250);
} catch (Exception e) {
e.printStackTrace();
}
changeTableValues();
}
}
private void changeTableValues() {
Runnable doRun = new Runnable() {
#Override
public void run() {
table.getModel().setValueAt(random.nextInt(128) + random.nextDouble(), 0, 1);
table.getModel().setValueAt(random.nextInt(256) + random.nextDouble(), 1, 1);
table.getModel().setValueAt(random.nextInt(512) + random.nextDouble(), 2, 1);
table.getModel().setValueAt(random.nextInt(128), 0, 2);
table.getModel().setValueAt(random.nextInt(128), 1, 2);
table.getModel().setValueAt(random.nextInt(128), 2, 2);
}
};
SwingUtilities.invokeLater(doRun);
}
private class MyTask extends SwingWorker<Void, Integer> {
private static final String UPDATE_TABLE_COLUMN = "update";
private String namePr;
private double dbl;
MyTask(String str) {
this.namePr = str;
}
#Override
protected Void doInBackground() throws Exception {
dbl = ((Double) table.getModel().getValueAt(1, 1))
- ((Integer) table.getModel().getValueAt(1, 2));
return null;
}
#Override
protected void done() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
table.getModel().setValueAt(dbl, 1, 3);
}
});
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ChangeNotifiersOnEvent frame = new ChangeNotifiersOnEvent();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocation(150, 150);
frame.pack();
frame.setVisible(true);
}
});
}
}
.
notice
required to set proper value for getColumnClass to Integer, Long or Double
proper of ways is only usage of AbstractTableModel (easiest as override this event in DefaultTableModel), there to override getValueAt(),
inside getValueAt() only calculate proper formula for desired column
I'd be disable JTable.getTableHeader().setReorderingAllowed(false);, otherwise have to setModelIndex or before calculations
Get the value from the table model. getModel().getValueAt(..)
Call getValueAt(int row, int column). May return null for empty cells. Do not call this on the model as the table row number may not match the model row number if sorting is enabled and applied. Also the table column number may not match the model column number if table columns have been rearranged.

Error in getRowCount() on DefaultTableModel

EDIT
I've tried changing the table model back to DefaultTableModel but I am getting an Exception when compiling my code and I can't figure out why!
Here's my table init:
jTable1.setModel(new Table1Model());
jTable1.setDefaultRenderer(Color.class,new ColorRenderer(true));
jTable1.getColumnModel().getColumn(5).setCellEditor(new ColorEditor());
My class extending the model:
class Table1Model extends DefaultTableModel {
//private String[] columnNames = {"Station #",
private Object[] columnNames = {"Station #",
"Name",
"avg Time",
"Buffer",
"Buffer Parts",
"Color"};
private Object[][] data = {
{"1", "Station 1",
new Integer(10), false, new Integer(0), Color.red},
{"2", "Station 2",
new Integer(10), false, new Integer(0), Color.blue},
{"3", "Station 3",
new Integer(10), false, new Integer(0), Color.green},
{"4", "Station 4",
new Integer(10), false, new Integer(0), Color.orange},
{"5", "Station 5",
new Integer(10), false, new Integer(0), Color.black}
};
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
//int length = data.length;
//int datalength = Integer.parseInt(length);
return data.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col].toString();
}
#Override
public Object getValueAt(int row, int col) {
return data[row][col];
}
/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,
* then the last column would contain text ("true"/"false"),
* rather than a check box.
*/
#Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don't need to implement this method unless your table's
* editable.
*/
#Override
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col == 0) { return false; }
else if (col == 4) {
boolean di = (Boolean) getValueAt(row,(col-1));
if (!di) { return false; }
else { return true; }
}
else { return true; }
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
/*public void removeRow(int row) {
data.removeRow(row);
}*/
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
This generates the following error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at SimGui$Table1Model.getRowCount(SimGui.java:863)
at javax.swing.table.DefaultTableModel.setDataVector(DefaultTableModel.java:224)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:124)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:106)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:86)
at SimGui$Table1Model.<init>(SimGui.java:832)
at SimGui.initComponents(SimGui.java:265)
at SimGui.<init>(SimGui.java:34)
at SimGui$16.run(SimGui.java:789)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:701)
at java.awt.EventQueue.access$000(EventQueue.java:102)
at java.awt.EventQueue$3.run(EventQueue.java:662)
at java.awt.EventQueue$3.run(EventQueue.java:660)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:671)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
Can you help me figure out what's wrong?
Also, will I be able to use the ColorEditor with the DefaultTableModel?
You have two obvious choices here: either give your class a getVectorData() method or else give it another similarly useful method that allows you to extract the nucleus of your data from your model. You probably shouldn't use an AbstractTableModel variable though but rather use a variable of your own custom type that extends AbstractTableModel to allow you to be able to call custom methods of your model.
i.e.,
MyTableModel model = (MyTableModel)jTable1.getModel();
SomeCollection myKeyData = model.getMyKeyData();
Also, this statement:
I have recently created my own class to extend AbstractTableModel to be able to insert some logic on isCellEditable and setValueAt.
Doesn't make sense to me since you could always use a DefaultTableModel and simply override those two methods. But if you use a DefaultTableModel, don't also have it hold the 2D array of object as you're trying to do. Rather feed the data into its internal data via the appropriate constructor or via its addRow(...) method. Else you lose all the power that DefaultTableModel has to offer.
Edit
If you want to use a DefaultTableModel to leverage its methods, then you cannot use a separate data "nucleus" for your model (here your Object[][]), but instead must load your data into the model that is held inside of the DefaultTableModel super class. This can be done either via the correct super constructor or by adding rows of data using its addRow(...) method.
For example, here I load your data into a DefaultTableModel override:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.table.*;
public class TableModelTest extends JPanel {
private static final Object[][] DATA = {
{ "1", "Station 1", new Integer(10), false, new Integer(0), Color.red },
{ "2", "Station 2", new Integer(10), false, new Integer(0), Color.blue },
{ "3", "Station 3", new Integer(10), false, new Integer(0),
Color.green },
{ "4", "Station 4", new Integer(10), false, new Integer(0),
Color.orange },
{ "5", "Station 5", new Integer(10), false, new Integer(0),
Color.black } };
private MyTableModel myTableModel = new MyTableModel(DATA);
private JTable table = new JTable(myTableModel);
public TableModelTest() {
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
table.getColumnModel().getColumn(5)
.setCellRenderer(new ColorCellRenderer());
table.getColumnModel().getColumn(5).setCellEditor(new ColorCellEditor());
}
private static void createAndShowGui() {
TableModelTest mainPanel = new TableModelTest();
JFrame frame = new JFrame("TableModelTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ColorCellEditor extends AbstractCellEditor implements TableCellEditor {
Color currentColor;
JButton button;
JColorChooser colorChooser;
JDialog dialog;
protected static final String EDIT = "edit";
public ColorCellEditor() {
ActionListener actionListener = new MyActionListener();
button = new JButton();
button.setActionCommand(EDIT);
button.addActionListener(actionListener);
button.setBorderPainted(false);
colorChooser = new JColorChooser();
dialog = JColorChooser.createDialog(button, "Pick a Color", true,
colorChooser, actionListener, null);
}
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (EDIT.equals(e.getActionCommand())) {
button.setBackground(currentColor);
colorChooser.setColor(currentColor);
dialog.setVisible(true);
fireEditingStopped();
} else {
currentColor = colorChooser.getColor();
}
}
}
public Object getCellEditorValue() {
return currentColor;
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
currentColor = (Color) value;
return button;
}
}
class ColorCellRenderer implements TableCellRenderer {
private static final int IMG_WIDTH = 70;
private static final int IMG_HEIGHT = 20;
private JLabel label = new JLabel();
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean arg2, boolean arg3, int arg4, int arg5) {
Color color = (Color) value;
BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
g.setColor(color);
g.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);
g.dispose();
ImageIcon icon = new ImageIcon(img);
label.setIcon(icon);
return label;
}
}
class MyTableModel extends DefaultTableModel {
private static final String[] COLUMN_NAMES = { "Station #", "Name",
"avg Time", "Buffer", "Buffer Parts", "Color" };
public MyTableModel(Object[][] data) {
super(data, COLUMN_NAMES);
}
#Override
public boolean isCellEditable(int row, int col) {
if (col == 0) {
return false;
} else if (col == 4) {
boolean di = (Boolean) getValueAt(row, (col - 1));
if (!di) {
return false;
} else {
return true;
}
} else {
return true;
}
}
public void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
Object datum = getValueAt(i, j);
// System.out.print(" " + data[i][j]);
System.out.print(" " + datum);
}
System.out.println();
}
System.out.println("--------------------------");
}
}

Categories