I am under the impression that after column 4 [index 3] the rest of my jtable does react to formatting or data validation.
As you can see in this image the colour just stops after column 4:
Declaration:
private final JTable table = new JTable(new TableModelDB("all"));
private final JScrollPane scrollPane = new JScrollPane(table);
Here is all my code relating to the jtable:
JFormattedTextField ftext = new JFormattedTextField();
try {
MaskFormatter mask = new MaskFormatter("####-##-##");
mask.setPlaceholderCharacter('_');
mask.setAllowsInvalid(false);
mask.install(ftext);
} catch (ParseException e) {
System.out.println("error: " + e);
}
table.setDefaultEditor(Object.class, new MyCellEditor());
table.getColumnModel().getColumn(3).setCellEditor(new MyCellEditor(ftext));
table.setRowHeight(30);
table.setFillsViewportHeight(true);
table.getModel().addTableModelListener(this);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setDefaultRenderer(Object.class, cr);
table.setAutoCreateColumnsFromModel(false);
resizeColumnWidth();
table.getTableHeader().setFont(new Font("Arial", Font.BOLD, 20));
table.setFont(new Font("Arial", Font.PLAIN, 20));
Data Validation using CellEditor (The validation works just fine until column=4, using println() I figured out that the stopCellEditing method was never called):
private boolean editValidation(String data) {
System.out.println("editValidation");
int column = table.getSelectedColumn();
if (data == null || data.trim().isEmpty()) {
System.out.println("c0");
JOptionPane.showMessageDialog(null, "Cannot leave a field blank");
return false;
}
if (column == 1 && data.length() > 255) {
JOptionPane.showMessageDialog(null, "The Income name is too long (Max 255 characters)");
return false;
}
if (column == 2 && data.length() > 255) {
JOptionPane.showMessageDialog(null, "The Category name is too long (Max 255 characters)");
return false;
}
if (column == 3) {
if (data.contains("_")) {
JOptionPane.showMessageDialog(null, "Invalid date");
return false;
} else {
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
df.parse(data);
} catch (ParseException e) {
JOptionPane.showMessageDialog(null, "Invalid date");
return false;
}
}
}
if (column == 4) {
System.out.println("c4");
if (!data.matches("^[0-9]+")) {
JOptionPane.showMessageDialog(null, "Amount contains non-number elements");
return false;
} else if (Integer.parseInt(data) <= 0) {
JOptionPane.showMessageDialog(null, "Income cannot be less than or equal to zero");
return false;
}
}
return true;
}
public class MyCellEditor extends DefaultCellEditor {
public MyCellEditor() {
super(new JTextField());
}
MyCellEditor(JFormattedTextField ftext) {
super(ftext);
}
#Override
public boolean stopCellEditing() {
System.out.println("stopCellEditing");
final JTextField field = (JTextField) getComponent();
if (editValidation(field.getText())) {
System.out.println("case t");
field.setBackground(Color.WHITE);
return super.stopCellEditing();
}
System.out.println("case f");
Toolkit.getDefaultToolkit().beep();
field.setBackground(Color.RED);
return false;
}
}
Cell Renderer (even though I made everything light grey, the columns after index 3 weren't applied):
public class CustomCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, col);
c.setBackground(Color.LIGHT_GRAY);
// if (col == 0) {
// c.setBackground(Color.LIGHT_GRAY);
// } else {
// c.setBackground(Color.WHITE);
// }
return c;
}
}
Table Model:
public final class TableModelDB extends AbstractTableModel {
private final WorkingClass wc = new WorkingClass();
private final int startRows = 1;
private final String[] columnNames = {"Income ID", "Income Name", "Category", "Entry Date", "Amount", "Delete"};
private Object[][] data;
public TableModelDB(String type) {
try {
ResultSet rs = wc.searchIncomeRS(type);
int rowCount = wc.rowCount();
int count = 0, amount, total = 0;
Object[][] temp = new Object[rowCount + startRows][6];
while (rs.next()) {
temp[count][0] = rs.getString("ID");
temp[count][1] = rs.getString("EntryName");
temp[count][2] = rs.getString("Category");
Date date = new Date(rs.getDate("EntryDate").getTime());
temp[count][3] = wc.strDate(date);
amount = rs.getInt("Amount");
total += amount;
temp[count][4] = amount;
temp[count++][5] = false;
}
temp[count][4] = total;
data = temp;
} catch (SQLException ex) {
System.out.println("error: " + ex);
}
}
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 col) {
for (int row = 0; row < getRowCount(); row++) {
Object o = getValueAt(row, col);
if (o != null) {
return o.getClass();
}
}
return Object.class;
}
public boolean isCellEditable(int row, int col) {
return !(data[row][col] == null || data[row][0] == null || col == 0);
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
If any kind soul could tell me why the columns don't respond it would be greatly appreciated, any other errors or criticism are welcomed too
Thank you very much :)
After creating a few test classes I realised only columns with Strings got the formatting and the DV, so I changed it to:
table.setDefaultEditor(String.class, new MyCellEditor());//DV
table.setDefaultEditor(Integer.class, new MyCellEditor());//DV
table.setDefaultEditor(Boolean.class, new MyCellEditor());//DV
table.getColumnModel().getColumn(3).setCellEditor(new MyCellEditor(ftext));//Mask
table.setDefaultRenderer(String.class, new CustomCellRenderer());//color
table.setDefaultRenderer(Integer.class, new CustomCellRenderer());//color
table.setDefaultRenderer(Boolean.class, new CustomCellRenderer());//color
Now everything works
Related
I have Custom Components extended from JPanel.
The name are: PanelButton and PanelSlider
QUESTION 1:
Is it valid (or secure) to create a xxxTableModel(...) with nonuniform Matrix?
String[] hdrsObjects = {"PanelButton Class", "PanelSlider Class"};
Object[][] objectMatrix = new Object[3][2];
objectMatrix[0][0] = new PanelButtonData(...);
objectMatrix[1][0] = new PanelButtonData(...);
objectMatrix[2][0] = new PanelButtonData(...);
// objectMatrix[0][1] = /*Non Assigned*/
objectMatrix[1][1] = new PanelSliderData(0, 20, 40);
objectMatrix[2][1] = new PanelSliderData(30, 40, 60);
JTable Mytable = new JTable(new MyTableModel(objectMatrix, hdrsObjects)) {...}
That's equivalent to 3 Rows with different lengths:
jtblGeneral.setModel(new DefaultTableModel(
new Object [][] { {"Cell Row:0,Col:0"}, {"Cell Row:1,Col:0", "Cell Row:1,Col:1"}, {"Cell Row:2,Col:0", "Cell Row:2,Col:1"}
},
new String [] {
"Title 1", "Title 2"
}
));
Now I'm implementing my own TableCellRenderer
class MyTableCellRenderer implements TableCellRenderer {
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
#Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
return ps;
}
//if (value != null)
// return (Component) value;
//return this;
//return null;
// return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
// table, value, isSelected, hasFocus, row, column);
return new JLabel();
}
}
QUESTION 2:
If Answer is YES for before Question. When the value is null and not defined (like cell in row:0, col:1) in my custom JPanel Classes, what Type Object I must return?
return null; When I return null (I will have problem with Nimbus and GTK Look And Feels)
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); or
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
Here the Exception java.lang.NullPointerException:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
return new JLabel();
return new Component();
QUESTION 3:
But, When the value Is not null and I don't know the Class type, How handle the return?
if (value != null) return (Component) value;
return table.getDefaultRenderer(String.class).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
extend my MyTableCellRenderer class of Component and return this;
ALL CODE
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableButtonSlider extends JFrame {
public TableButtonSlider() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(600, 300);
setVisible(true);
setLocationRelativeTo(null);
}
public static void setLAF(Container container, String laf) {
try {
UIManager.setLookAndFeel(laf);
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
}
SwingUtilities.updateComponentTreeUI(container);
}
static final JFrame frame = new JFrame();
public JComponent makeUI() {
String[] hdrsObjects = {"PanelButton Class", "PanelSlider Class"};
Object[][] objectMatrix = new Object[3][2];
objectMatrix[0][0] = new PanelButtonData(true);
objectMatrix[1][0] = new PanelButtonData(false);
objectMatrix[2][0] = new PanelButtonData(false);
// objectMatrix[0][1] = new PanelSliderData(10, 30, 40);
objectMatrix[1][1] = new PanelSliderData(0, 20, 40);
objectMatrix[2][1] = new PanelSliderData(30, 40, 60);
JTable Mytable = new JTable(new MyTableModel(objectMatrix, hdrsObjects)) {
#Override public void updateUI() {
super.updateUI();
setRowHeight(30);
TableColumn tc;
tc = getColumn("PanelSlider Class");
tc.setCellRenderer(new MyTableCellRenderer());
tc.setCellEditor(new MyTableCellEditor());
tc = getColumn("PanelButton Class");
tc.setCellRenderer(new MyTableCellRenderer());
tc.setCellEditor(new MyTableCellEditor());
}
};
JScrollPane scrollPane = new JScrollPane(Mytable);
JPanel pH = new JPanel();
pH.setLayout(new BoxLayout(pH, BoxLayout.LINE_AXIS));
JPanel pV = new JPanel();
pV.setLayout(new BoxLayout(pV, BoxLayout.PAGE_AXIS));
JButton bInsert = new JButton("Insert");
bInsert.addActionListener((ActionEvent e) -> {
((MyTableModel)Mytable.getModel()).addRow(
new Object[] {
new PanelButtonData(false),
new PanelSliderData(0, 25, 50)
}
);
Mytable.updateUI();
});
JButton bMetal = new JButton("Metal");
bMetal.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "javax.swing.plaf.metal.MetalLookAndFeel");
});
JButton bMotif = new JButton("Motif");
bMotif.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
});
JButton bNimbus = new JButton("Nimbus");
bNimbus.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "javax.swing.plaf.nimbus.NimbusLookAndFeel");
});
JButton bMacOS = new JButton("mac");
bMacOS.addActionListener((ActionEvent evt) -> {
setLAF(TableButtonSlider.this, "com.apple.laf.AquaLookAndFeel");
});
JButton bWindows = new JButton("win");
bWindows.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
});
JButton bLinux = new JButton("lnx");
bLinux.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
});
pH.add(bInsert);
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(new JSeparator(JSeparator.VERTICAL));
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(bLinux);
pH.add(bMacOS);
pH.add(bWindows);
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(new JSeparator(JSeparator.VERTICAL));
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(bMetal);
pH.add(bMotif);
pH.add(bNimbus);
pV.add(pH);
pV.add(scrollPane);
return pV;
}
public static void main(String... args) {
UIManager.put("Slider.paintValue", false);
EventQueue.invokeLater(() -> {
TableButtonSlider f = new TableButtonSlider();
f.getContentPane().add(f.makeUI());
});
}
}
class PanelButton extends JPanel {
JButton jbtWavRow = new JButton();
private final JPanel panel = new JPanel();
PanelButton(PanelButtonData data) {
super();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createRigidArea(new Dimension(2,0)));
panel.add(jbtWavRow);
panel.add(Box.createRigidArea(new Dimension(2,0)));
jbtWavRow.setFont(new Font("Monospaced", Font.PLAIN, 10));
setData(data);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(panel);
}
public PanelButtonData getData() {
return new PanelButtonData(jbtWavRow.getActionCommand().equals("+"));
}
public void setData(PanelButtonData data) {
for (ActionListener al : jbtWavRow.getActionListeners()) {
jbtWavRow.removeActionListener(al);
}
if(data.getIns()) {
jbtWavRow.setText("Insert");
jbtWavRow.setActionCommand("+");
jbtWavRow.addActionListener((ActionEvent e) -> {
JTable table = (JTable)SwingUtilities.getAncestorOfClass(
JTable.class, (Component) e.getSource());
table.getCellEditor().stopCellEditing();
((MyTableModel)table.getModel()).addRow(
new Object[] {
new PanelButtonData(false),
new PanelSliderData(0, 25, 50)
}
);
table.updateUI();
});
} else {
jbtWavRow.setText("Remove");
jbtWavRow.setActionCommand("-");
jbtWavRow.addActionListener((ActionEvent e) -> {
JTable table = (JTable) SwingUtilities.getAncestorOfClass(
JTable.class, (Component) e.getSource());
int row = table.getEditingRow();
table.getCellEditor().stopCellEditing();
((MyTableModel) table.getModel()).removeRow(row);
// table.updateUI();
});
}
}
}
class PanelButtonData {
private boolean add = false;
PanelButtonData(Boolean add) { this.add = add; }
public void setIns(Boolean add) { this.add = add; }
public boolean getIns() { return add; }
}
class PanelSlider extends JPanel {
private final JSlider jslChanger = new JSlider(SwingConstants.HORIZONTAL);
private final JPanel panel = new JPanel();
PanelSlider(PanelSliderData data) {
super();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createRigidArea(new Dimension(2,0)));
panel.add(jslChanger);
panel.add(Box.createRigidArea(new Dimension(2,0)));
setData(data);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(panel);
}
public void setData(PanelSliderData data) {
jslChanger.setMinimum(data.getMin());
jslChanger.setValue(data.getVal());
jslChanger.setMaximum(data.getMax());
}
// Used in MyTableCellRenderer.getCellEditorValue()
public PanelSliderData getData() {
return new PanelSliderData(jslChanger.getMinimum(), jslChanger.getValue(), jslChanger.getMaximum());
}
}
class PanelSliderData {
private Integer Min = 0;
private Integer Val = 25;
private Integer Max = 50;
PanelSliderData(int Min, int Val, int Max) {
this.Min = Min;
this.Val = Val;
this.Max = Max;
}
public Integer getMin() { return Min; }
public Integer getVal() { return Val; }
public Integer getMax() { return Max; }
}
class MyTableCellRenderer implements TableCellRenderer {
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
#Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
return ps;
}
//if (value != null)
// return (Component) value;
//return this;
return null;
//return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
// table, value, isSelected, hasFocus, row, column);
//return new JLabel();
}
}
class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
protected Object output;
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
#Override public Object getCellEditorValue() {
if (output instanceof PanelButton) {
return pb.getData();
}
if (output instanceof PanelSlider) {
return ps.getData();
}
return null;
}
#Override public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
output = pb;
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
output = ps;
return ps;
}
return null;
}
}
class MyTableModel extends AbstractTableModel {
//class MyTableModel extends DefaultTableModel {
private Object[][] data;
private Object[] columns;
public MyTableModel(Object[][] data, Object[] columns) {
this.data = data;
this.columns = columns;
}
#Override public Object getValueAt(int rowIndex, int columnIndex) {
if (data != null) {
if (data.length > 0) {
return data[rowIndex][columnIndex];
}
}
return null;
}
#Override public int getColumnCount() {
return ((columns == null) ? 0: columns.length);
}
#Override public int getRowCount() {
return ((data == null) ? 0: data.length);
}
#Override public Class getColumnClass(int columnIndex) {
if (data != null) {
if (data.length > 0) {
if (data[0][columnIndex] instanceof PanelButton) {
return PanelButton.class;
}
if (data[0][columnIndex] instanceof PanelSlider) {
return PanelSlider.class;
}
//return data[0][columnIndex].getClass();
return String.class;
}
}
return Object.class;
}
#Override public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
#Override public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
#Override public String getColumnName(int columnIndex) {
return (String)columns[columnIndex];
}
//#Override
public void removeRow(int row) {
Object[][] newData = new Object[data.length - 1][data[0].length];
int rown = 0;
for (int row1 = 0; row1 <data.length; row1++) {
if (row1 != row) {
for (int col = 0; col < data[0].length; col++) {
newData[rown][col] = data[row1][col];
}
rown++;
}
}
data = newData;
}
//#Override
public void addRow(Object[] rowData) {
Object[][] newData;
int maxCol;
if ((data != null) && (data.length > 0)) {
newData = new Object[data.length + 1][data[0].length];
for (int row = 0; row <data.length; row++) {
for (int col = 0; col < data[0].length; col++) {
newData[row][col] = data[row][col];
}
}
maxCol = data[0].length < rowData.length?data[0].length:rowData.length;
} else {
newData = new Object[1][rowData.length];
maxCol = rowData.length;
}
//Insert rowData objects
for (int col = 0; col < maxCol; col++) {
newData[newData.length - 1][col] = rowData[col];
}
data = newData;
}
}
EDIT 1
public static void main(String... args) {
UIManager.put("Slider.paintValue", false);
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) { }
EventQueue.invokeLater(() -> {
TableButtonSlider f = new TableButtonSlider();
f.getContentPane().add(f.makeUI());
});
}
Establishing the nimbus LookAndFeel like first operation on main method the Exception raise up:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JViewport.paint(JViewport.java:728)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent.paint(JComponent.java:1042)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
at java.awt.Container.paint(Container.java:1975)
at java.awt.Window.paint(Window.java:3904)
at javax.swing.RepaintManager$4.run(RepaintManager.java:842)
at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Is it valid (or secure) to create a xxxTableModel(...) with nonuniform Matrix?
Yes, you can do it, but it requires a lot of effort on your part to make it work, as JTable really isn't designed to work this way
If Answer is YES for before Question. When the value is null and not defined (like cell in row:0, col:1) in my custom JPanel Classes, what Type Object I must return?
You MUST return an instance of Component, you can NOT return null
But, When the value Is not null and I don't know the Class type, How handle the return?
This is the same answer as your second question, you MUST return an instance of Component, it's up to you as to how you want to handle the difference between null and "unknown" values
Obsrvations
After digging through your code, you are making calls to updateUI which are inappropriate, this is not a means to trigger a "update" to the UI when you change it's state, it's only meant to be used (by the system) to inform components that the Look and Feel delegate has been changed
In your TableModel, you should be firing appropriate events when the model is update, this will notify the parent JTable and it will make appropriate changes.
I removed ALL the calls to updateUI in your code and simply updated your addRow method to call fireTableRowsInserted
public void addRow(Object[] rowData) {
Object[][] newData;
int maxCol;
if ((data != null) && (data.length > 0)) {
newData = new Object[data.length + 1][data[0].length];
for (int row = 0; row < data.length; row++) {
for (int col = 0; col < data[0].length; col++) {
newData[row][col] = data[row][col];
}
}
maxCol = data[0].length < rowData.length ? data[0].length : rowData.length;
} else {
newData = new Object[1][rowData.length];
maxCol = rowData.length;
}
//Insert rowData objects
for (int col = 0; col < maxCol; col++) {
newData[newData.length - 1][col] = rowData[col];
}
data = newData;
fireTableRowsInserted(data.length - 1, data.length - 1);
}
and the NullPointerException went away. You have to make appropriate changes to removeRow as well
I don't know how to go about i have this frame i wish to populate a JTable and add a checkbox.
public static void update_table() {
try {
String sql="SELECT * FROM equipments";
PreparedStatement update = con.prepareStatement(sql);
ResultSet result = update.executeQuery();
table.setModel(DbUtils.resultSetToTableModel(result));
table.setVisible(true);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I assume you mean to want to add an additional column not found in the database containing a check box so you can select rows?
If so then you can use a wrapper TableModel.
Here is an example that might help:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class CheckBoxWrapperTableModel extends AbstractTableModel
{
private ArrayList<Boolean> checkBoxes = new ArrayList<>();
private DefaultTableModel model;
private String columnName;
public CheckBoxWrapperTableModel(DefaultTableModel model, String columnName)
{
this.model = model;
this.columnName = columnName;
for (int i = 0; i < model.getRowCount(); i++)
checkBoxes.add( Boolean.FALSE );
}
#Override
public String getColumnName(int column)
{
return (column > 0) ? model.getColumnName(column - 1) : columnName;
}
#Override
public int getRowCount()
{
return model.getRowCount();
}
#Override
public int getColumnCount()
{
return model.getColumnCount() + 1;
}
#Override
public Object getValueAt(int row, int column)
{
if (column > 0)
return model.getValueAt(row, column - 1);
else
{
Object value = checkBoxes.get(row);
return (value == null) ? Boolean.FALSE : value;
}
}
#Override
public boolean isCellEditable(int row, int column)
{
if (column > 0)
return model.isCellEditable(row, column - 1);
else
return true;
}
#Override
public void setValueAt(Object value, int row, int column)
{
if (column > 0)
model.setValueAt(value, row, column - 1);
else
{
checkBoxes.set(row, (Boolean)value);
}
fireTableCellUpdated(row, column);
}
#Override
public Class getColumnClass(int column)
{
return (column > 0) ? model.getColumnClass(column - 1) : Boolean.class;
}
public void removeRow(int row)
{
checkBoxes.remove(row);
fireTableRowsDeleted(row, row);
model.removeRow(row);
}
private static void createAndShowGUI()
{
// Create the table with check marks in the first column
DefaultTableModel model = new DefaultTableModel(5, 1);
for (int i = 0; i < model.getRowCount(); i++)
{
model.setValueAt("" + i, i, 0);
}
CheckBoxWrapperTableModel wrapperModel = new CheckBoxWrapperTableModel(model, "Select");
JTable table = new JTable(wrapperModel);
// Add button to delete selected rows
JButton button = new JButton( "Delete Selected Rows" );
button.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
for (int i = table.getRowCount() - 1; i >= 0; i--)
{
Boolean selected = (Boolean)table.getValueAt(i, 0);
System.out.println(selected + " : " + i);
if (selected)
{
wrapperModel.removeRow(i);
}
}
}
});
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new JScrollPane( table ) );
frame.add( button, BorderLayout.PAGE_END );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
If the model works then you would us the model with code like:
//table.setModel(DbUtils.resultSetToTableModel(result));
TableModel utilsModel = DbUtils.resultSetToTableModel(result);
TableModel wrapperModel = new CheckBoxWrapperTableModel(utilsModel, "Select");
table.setModel( wrapperModel );
This issue is hurting me for a long time.
It is very nasty and I managed to prepare sample that will show it to you expert.
Just copy paste this :
public class CellBorderDemo extends JFrame
{
private JTable dataSearchResultTable;
private boolean selectRow = false;
public CellBorderDemo()
{
JPanel panel = new JPanel(new GridLayout(2, 1, 5, 10));
panel.setPreferredSize(new Dimension(500, 300));
MyTableModel myTableModel = new MyTableModel();
dataSearchResultTable = new JTable();
dataSearchResultTable.addKeyListener(new KeyAdapter()
{
private String attemptId = new String();
#Override
public void keyTyped(KeyEvent e)
{
System.out.println("selectRow=" + selectRow + " keyChar=" + (int) e.getKeyChar() + " event=" + e);
if ((e.getModifiers() == KeyEvent.CTRL_MASK && (int) e.getKeyChar() == 10)) {
System.out.println("Ctrl+J was pressed when focus was ok");
selectRow = true;
attemptId = new String();
dataSearchResultTable.editCellAt(-1, -1);
dataSearchResultTable.getSelectionModel().clearSelection();
return;
} else if ((int) e.getKeyChar() == 32) {
return;
}
if (selectRow) {
char keyChar = e.getKeyChar();
if (keyChar >= 48 && keyChar <= 57) {
attemptId += String.valueOf(keyChar);
if (selectRow(Integer.valueOf(attemptId).intValue())) {
System.out.println("attemptId=" + attemptId);
return;
}
}
selectRow = false;
attemptId = new String();
}
}
});
dataSearchResultTable.setSelectionBackground(new Color(0xbbccdd));
dataSearchResultTable.setSelectionForeground(new Color(0x333300));
dataSearchResultTable.setFillsViewportHeight(true);
dataSearchResultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
dataSearchResultTable.setAutoCreateRowSorter(true);
dataSearchResultTable.setRowHeight(30);
dataSearchResultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
dataSearchResultTable.getColumnModel().setColumnMargin(0);
dataSearchResultTable.setPreferredScrollableViewportSize(dataSearchResultTable.getPreferredSize());
dataSearchResultTable.setModel(myTableModel);
panel.add(new JScrollPane(dataSearchResultTable));
super.getContentPane().add(panel);
super.pack();
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
super.setVisible(true);
}
public boolean selectRow(int attemptId)
{
MyTableModel tableModel = (MyTableModel) dataSearchResultTable.getModel();
int row = 0;
if (attemptId >= 0 && attemptId < tableModel.getRowCount()) {
System.out.println("rowToSelect=" + row);
dataSearchResultTable.setRowSelectionInterval(attemptId, attemptId);
dataSearchResultTable.setColumnSelectionInterval(2, 2);
tableModel.fireTableCellUpdated(row, 2);
dataSearchResultTable.requestFocusInWindow();
return true;
}
return false;
}
class MyTableModel extends AbstractTableModel
{
private String[] columnNames = { "First Name", "Last name", "Vegetarian" };
private Object[][] data;
int prefRow = 1, prefCol = 2;
MyTableModel()
{
data = new Object[][] { { "Vova", "KipokKipokKipokKipok", false }, { "Olia", "Duo", true },
{ "Ivan", "Brown", false } };
}
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)
{
if (data.length > 0 && data[0] != null) {
return data[row][col];
}
return null;
}
public Class getColumnClass(int c)
{
Object valueAt = getValueAt(0, c);
return valueAt == null ? Object.class : valueAt.getClass();
}
public boolean isCellEditable(int row, int col)
{
return true;
}
public void setValueAt(Object value, int row, int col)
{
if (data.length > 0 && data[0] != null) {
if (data[row][col] instanceof Boolean && (Boolean) value) {
setValueAt(false, prefRow, prefCol);
prefRow = row;
prefCol = col;
}
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
}
public static void main(String[] args) throws ParseException
{
new CellBorderDemo();
}
}
I understand that it's long. Don't look at class MyTableModel at all but only at keylistener and selectRow method.
Now please press Ctrl+J and then press either 0 or 1 or 2.
You will notice that appropriate row is selected you may press Space to select checkbox. Now press Ctrl+J again and press number from 0 to 2 but it should be different from the first attempt. You notice that new row is selected according to new number . And now press Space and you will see my issue new cell was selected but wasn't focused and that's why Space unselected previously selected checkbox but not currently selected one.
I will be very grateful for this help because this feature is very important.
Thank you!
Problem in next in your selectRow method you never change your row variable it always 0. In next example i change your row variable and try to edit that row with editCellAt method
public boolean selectRow(int attemptId) {
MyTableModel tableModel = (MyTableModel) dataSearchResultTable.getModel();
int row = 0;
if (attemptId >= 0 && attemptId < tableModel.getRowCount()) {
System.out.println("rowToSelect=" + row);
dataSearchResultTable.setRowSelectionInterval(attemptId, attemptId);
dataSearchResultTable.setColumnSelectionInterval(2, 2);
tableModel.fireTableCellUpdated(row, 2);
dataSearchResultTable.requestFocusInWindow();
row = dataSearchResultTable.getSelectedRow();
if(row != -1){
dataSearchResultTable.editCellAt(row, 2);
}
return true;
}
return false;
}
I think it what do you want.
I have been thinking a lot to solve this mistake. But unfortunately I came to final cnclusion that I need help of professionals.
Please, copy,paste this code to see issue:
public class DateFormatDemo extends JFrame
{
private JTable dataSearchResultTable;
public DateFormatDemo()
{
JButton updateTable = new JButton("Update table");
updateTable.setMaximumSize(updateTable.getPreferredSize());
updateTable.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
updateMyTableModel();
}
});
JPanel panel = new JPanel(new GridLayout(2, 1, 5, 10));
panel.setPreferredSize(new Dimension(500, 300));
panel.add(new JScrollPane(initDataSearchResultTable()));
panel.add(updateTable);
super.getContentPane().add(panel);
super.pack();
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
super.setVisible(true);
}
private JTable initDataSearchResultTable()
{
dataSearchResultTable = new JTable();
// dataSearchResultTable.setAutoCreateColumnsFromModel(false);
dataSearchResultTable.setSelectionBackground(new Color(0xaaaaff));
dataSearchResultTable.setFillsViewportHeight(true);
dataSearchResultTable.setRowSelectionAllowed(true);
dataSearchResultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
dataSearchResultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
return dataSearchResultTable;
}
void updateMyTableModel()
{
TableModel tableModel = dataSearchResultTable.getModel();
TableColumnModel columnModel = dataSearchResultTable.getColumnModel();
if (tableModel instanceof MyTableModel) {
((MyTableModel) tableModel).updateModel();
this.initColumnWidths(tableModel, columnModel);
} else {
tableModel = new MyTableModel();
dataSearchResultTable.setModel(tableModel);
this.makeColumnsNotResizable(columnModel);
this.initColumnWidths(tableModel, columnModel);
}
}
private void makeColumnsNotResizable(TableColumnModel columnModel)
{
for (int i = 0; i < columnModel.getColumnCount(); i++) {
if (i == 0 || i == 1) {
columnModel.getColumn(i).setResizable(false);
}
}
}
private void initColumnWidths(TableModel tableModel, TableColumnModel columnModel)
{
TableColumn column = null;
Component comp = null;
int cellWidth = 0;
int headerWidth = 0;
TableCellRenderer headerRenderer = dataSearchResultTable.getTableHeader().getDefaultRenderer();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
column = columnModel.getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, -1, 0);
headerWidth = comp.getPreferredSize().width;
Class<?> columnClass = tableModel.getColumnClass(i);
for (int j = 0; j < tableModel.getRowCount(); j++) {
comp = dataSearchResultTable.getDefaultRenderer(columnClass).getTableCellRendererComponent(
dataSearchResultTable, tableModel.getValueAt(j, i), false, false, j, i);
int width = comp.getPreferredSize().width;
// we cache width of first row. And compare widths of next
// rows with width of first.
// If some row has greater width it becomes width of whole
// row(unless header has greater width)
if (cellWidth < width || j == 0) {
cellWidth = width;
}
}
System.out
.println("columnClass=" + columnClass + ",headerWidth=" + headerWidth + ",cellWidth=" + cellWidth);
if (headerWidth > cellWidth) {
TableCellRenderer centeredRenderer = dataSearchResultTable.getDefaultRenderer(columnClass);
if (centeredRenderer instanceof DefaultTableCellRenderer) {
((DefaultTableCellRenderer) centeredRenderer).setHorizontalAlignment(SwingConstants.CENTER);
column.setCellRenderer(centeredRenderer);
column.setPreferredWidth(headerWidth);
}
} else {
column.setPreferredWidth(cellWidth + 5);
}
}
}
class MyTableModel extends AbstractTableModel
{
private String[] columnNames = { "First Name", "Last Name", "Timestamp", "Number", "Vegetarian" };
private Object[][] data = new Object[5][];
void updateModel()
{
data = new Object[][] {
{ "Vova", "KipokKipokKipokKipok", "2013-04-12 11:20:41", new Integer(5), new Boolean(true) },
{ "Olia", "Duo", "2010-01-11 11:11:41", new Integer(3), new Boolean(false) },
{ "Oksana", "Stack", "2012-04-12 11:20:41", new Integer(2), new Boolean(false) },
{ "Petro", "White", "2010-04-12 11:20:21", new Integer(20), new Boolean(true) },
{ "Ivan", "Brown", "2011-04-11 11:20:41", new Integer(10), new Boolean(true) } };
fireTableDataChanged();
}
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)
{
if (data.length > 0 && data[0] != null) {
return data[row][col];
}
return null;
}
/*
* 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.
*/
public Class getColumnClass(int c)
{
Object valueAt = getValueAt(0, c);
return valueAt == null ? Object.class : valueAt.getClass();
}
/*
* Don't need to implement this method unless your table's editable.
*/
public boolean isCellEditable(int row, int col)
{
// Note that the data/cell address is constant,
// no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
/*
* Don't need to implement this method unless your table's data can
* change.
*/
public void setValueAt(Object value, int row, int col)
{
if (data.length > 0 && data[0] != null) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
}
public static void main(String[] args) throws ParseException
{
new DateFormatDemo();
}
}
Now please click twice on that big button called 'Update Table'. As you see column that should display checkbox as it holds boolean values do not do that but instead displays String true or false.
This code emulates my real workflow.
So, how to update tablemodel to have boolean columns with checkbozes.
Thanks!
take this as simple start point
import java.awt.*;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class Forum implements ListSelectionListener {
private JFrame frame = new JFrame("Frame");
private JPanel fatherCenter = new JPanel();
private JScrollPane tableScroll = new JScrollPane();
private MyTableModel tableModel;
private JTable dialogTable;
private ListSelectionModel lsDialog;
private Color clr;
private Color clr1;
private void addData() {
Runnable doRun1 = new Runnable() {
#Override
public void run() {
tableModel.resetTable();
Vector<String> tbl = new Vector<String>();
Vector<Object> tbl1 = new Vector<Object>();
Random rnd = new Random();
tbl.add("Integer");
tbl.add("Double");
tbl.add("Boolean");
tbl.add("Boolean");
tbl.add("String");
tableModel.setColumnNames(tbl);
for (int row = 0; row < 30; row++) {
tbl1 = null;
tbl1 = new Vector<Object>();
tbl1.addElement(row + 1);
tbl1.addElement(rnd.nextInt(25) + 3.14);
tbl1.addElement((row % 3 == 0) ? false : true);
tbl1.addElement((row % 5 == 0) ? false : true);
if (row % 7 == 0) {
tbl1.add(("Canc"));
} else if (row % 6 == 0) {
tbl1.add(("Del"));
} else {
tbl1.add(("New"));
}
tableModel.addRow(tbl1);
}
addTableListener();
}
};
SwingUtilities.invokeLater(doRun1);
}
private void addTableListener() {
tableModel.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent tme) {
if (tme.getType() == TableModelEvent.UPDATE) {
System.out.println("");
System.out.println("Cell " + tme.getFirstRow() + ", "
+ tme.getColumn() + " changed. The new value: "
+ tableModel.getValueAt(tme.getFirstRow(),
tme.getColumn()));
}
}
});
}
#Override
public void valueChanged(ListSelectionEvent le) {
int row = dialogTable.getSelectedRow();
int col = dialogTable.getSelectedColumn();
String str = "Selected Row(s): ";
int[] rows = dialogTable.getSelectedRows();
for (int i = 0; i < rows.length; i++) {
str += rows[i] + " ";
}
str += "Selected Column(s): ";
int[] cols = dialogTable.getSelectedColumns();
for (int i = 0; i < cols.length; i++) {
str += cols[i] + " ";
}
str += "Selected Cell: " + dialogTable.getSelectedRow() + ", " + dialogTable.getSelectedColumn();
System.out.println(str);
Object value = dialogTable.getValueAt(row, col);
System.out.println(String.valueOf(value));
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Forum osFrame = new Forum();
}
});
}
public Forum() {
tableModel = new MyTableModel();
dialogTable = new JTable(tableModel) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) comp;//for Custom JComponent
if (!isRowSelected(row)) {
int modelRow = convertRowIndexToModel(row);
boolean type = (Boolean) getModel().getValueAt(modelRow, 2);
boolean type1 = (Boolean) getModel().getValueAt(modelRow, 3);
comp.setForeground(Color.black);
if ((type) && (!type1)) {
comp.setBackground(clr1);
} else if ((!type) && (type1)) {
comp.setBackground(Color.orange);
} else if ((!type) || (!type1)) {
comp.setBackground(Color.red);
} else {
comp.setBackground(row % 2 == 0 ? getBackground() : getBackground().darker());
}
dialogTable.convertRowIndexToView(0);
} else {
comp.setForeground(Color.blue);
}
if (!isCellEditable(row, column)) {
comp.setForeground(Color.red);
comp.setBackground(Color.magenta);
}
return comp;
}
};
tableScroll = new JScrollPane(dialogTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tableScroll.setBorder(null);
dialogTable.getTableHeader().setReorderingAllowed(false);
dialogTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lsDialog = dialogTable.getSelectionModel();
dialogTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
dialogTable.setRowHeight(20);
dialogTable.setRowMargin(2);
dialogTable.setPreferredScrollableViewportSize(dialogTable.getPreferredSize());
ListSelectionModel rowSelMod = dialogTable.getSelectionModel();
//ListSelectionModel colSelMod = dialogTable.getColumnModel().getSelectionModel();
rowSelMod.addListSelectionListener(this);
//colSelMod.addListSelectionListener(this);
fatherCenter = new JPanel();
fatherCenter.setLayout(new BorderLayout(10, 10));
fatherCenter.add(tableScroll, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(10, 10));
frame.add(fatherCenter);
frame.setPreferredSize(new Dimension(400, 660));
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
addData();
}
private class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector<Vector<Object>> _data;
private Vector<String> _colNames;
private boolean[] _columnsVisible = {true, true, true, true, true};
public MyTableModel() {
_colNames = new Vector<String>();
_data = new Vector<Vector<Object>>();
}
public MyTableModel(Vector<String> colnames) {
_colNames = colnames;
_data = new Vector<Vector<Object>>();
}
public void resetTable() {
_colNames.removeAllElements();
_data.removeAllElements();
}
public void setColumnNames(Vector<String> colNames) {
_colNames = colNames;
fireTableStructureChanged();
}
public void addRow(Vector<Object> data) {
_data.add(data);
fireTableRowsInserted(_data.size() - 1, _data.size() - 1);
}
public void removeRowAt(int row) {
_data.removeElementAt(row);
fireTableRowsDeleted(row - 1, _data.size() - 1);
}
#Override
public int getColumnCount() {
return _colNames.size();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return Integer.class;
case 1:
return Double.class;
case 2:
return Boolean.class;
case 3:
return Boolean.class;
default:
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int colNum) {
switch (colNum) {
case 2:
return false;
default:
return true;
}
}
#Override
public String getColumnName(int colNum) {
return _colNames.get(colNum);
}
#Override
public int getRowCount() {
return _data.size();
}
#Override
public Object getValueAt(int row, int col) {
Vector<Object> value = _data.get(row);
return value.get(col);
}
#Override
public void setValueAt(Object newVal, int row, int col) {
Vector<Object> aRow = _data.elementAt(row);
aRow.remove(col);
aRow.insertElementAt(newVal, col);
fireTableCellUpdated(row, col);
}
public void setColumnVisible(int index, boolean visible) {
_columnsVisible[index] = visible;
fireTableStructureChanged();
}
}
}
Your problem in getColumnClass method as you see you also return Object because of that you also get String columns.
You can determine that method in next way:
#Override
public Class<?> getColumnClass(int arg0) {
return longValues[arg0].getClass();
}
Or return Classes for your columns in another way. But you must to determine this Classes while cunstruct your model.
I have a jtable that has a edit button, when i select a row and clicked to edit button and edit fields, and click to save button, that row doesn't update, And i have to refresh my table to Change that row!
My code:
if (e.getSource() == editButton) {
selectedRow = uTable.getSelectedRow();
if (selectedRow >= 0) {
editUser(selectedRow);
} else {
JOptionPane.showMessageDialog(null, "Select a row");
}
}
public void editUser(int row) {
UserInformation userInf = userModel.getSelectedMember(row);
NewUserFrame_Edit edit = new NewUserFrame_Edit(userInf, row);
}
...
My NewUserFrame_Edit Class :
public class NewUserFrame_Edit extends javax.swing.JFrame {
private AllUser userModel;
private int selectedrow;
private String gender;
public NewUserFrame_Edit(AllUser userModel,UserInformation userinf, int row) {
...
this.userModel = userModel;
jTextField1.setText(userinf.getFname().toString().trim());
jTextField2.setText(userinf.getLname().toString().trim());
if (userinf.getGender().equals("Male")) {
jRadioButton1.setSelected(true);
} else {
jRadioButton2.setSelected(true);
}
jTextField3.setText(userinf.getDate());
selectedrow = row;
setVisible(true);
}
private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {
userinf = new UserInformation();
userinf.setFname(jTextField1.getText());
userinf.setLname(jTextField2.getText());
userinf.setGender(gender);
userinf.setDate(jTextField3.getText());
userModel.setValueAt(userinf.getFname() , selectedrow, 1);
userModel.setValueAt(userinf.getLname() , selectedrow, 2);
userModel.setValueAt(userinf.getGender(), selectedrow , 3);
userModel.setValueAt(userinf.getDate() , selectedrow, 4);
userModel.updateFile(userModel.Udata);
NewUserFrame_Edit.this.dispose();
}
...
}
My setValueAt() and updateFile() methods of my model Class:
public class AllUser extends AbstractTableModel {
...
#Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
UserInformation userInfo = Udata.get(rowIndex);
switch (columnIndex) {
case 0:
userInfo.setID((String) value);
break;
case 1:
userInfo.setFname((String) value);
break;
case 2:
userInfo.setLname((String) value);
break;
case 3:
userInfo.setGender((String) value);
break;
case 4:
userInfo.setDate((String) value);
break;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
public void updateFile(ArrayList<UserInformation> data) {
PrintWriter pw;
try {
pw = new PrintWriter(new FileWriter("AllUserRecords.txt"));
for (UserInformation userinf : data) {
String line = userinf.getID()
+ " " + userinf.getFname()
+ " " + userinf.getLname()
+ " " + userinf.getGender()
+ " " + userinf.getDate();
pw.println(line);
}
pw.close();
} catch (IOException ioe) {
}
}
...
}
When i select a row and click to edit button, a new jframe is open that its text field is fill with older data, and i update data and click to save button.
Thus, my column is not certain.
I select a entire row, Not a cell!
Thanks.
For changing JTable entries, use TableModel#setValueAt. Calling fireTableDataChanged is unnecessary. This is for use internally within TableModel itself.
if (selectedRow >= 0) {
...
userModel.setValueAt(newValue, selectedRow, 0);
// ... more values for columns 1, 2, 3, etc.
} ...
You can create a method called updateRow(int index,String[] values) within your AbstractModel extending class and within it set new Value for each cell for that row using setValueAt(newValue,row,index). And within overridden setValue method of TableModel write fireTableCellUpdated(row, col).
Consider the Code Given below. Look at the updateRow and setValueAt method in MyModel class. And watch ((MyModel)myModel).updateRow(row,values);//update row written in MyMouseAdapter class.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.table.*;
class TableRowEdit extends JFrame
{
private JTable table;
private JScrollPane jsPane;
private TableModel myModel;
private JPanel dialogPanel;
private JTextField tf[];
private JLabel lbl[];
public void prepareAndShowGUI()
{
myModel = new MyModel();
table = new JTable(myModel);
jsPane = new JScrollPane(table);
table.getColumnModel().getColumn(2).setCellRenderer(new LabelCellRenderer());
table.addMouseListener(new MyMouseAdapter());
getContentPane().add(jsPane);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
prepareDialogPanel();
pack();
setVisible(true);
}
private void prepareDialogPanel()
{
dialogPanel = new JPanel();
int col = table.getColumnCount() - 1;
dialogPanel.setLayout(new GridLayout(col,2));
tf = new JTextField[col];
lbl = new JLabel[col];
for (int i = 0; i < col; i++)
{
lbl[i] = new JLabel(table.getColumnName(i));
tf[i] = new JTextField(10);
dialogPanel.add(lbl[i]);
dialogPanel.add(tf[i]);
}
}
private void populateTextField(String[] s)
{
for (int i = 0 ; i < s.length ; i++ )
{
tf[i].setText(s[i]);
}
}
public class LabelCellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent(JTable table,Object oValue, boolean isSelected, boolean hasFocus, int row, int column)
{
Component c = super.getTableCellRendererComponent(table, oValue,isSelected, hasFocus,row, column);
String value = (String)oValue;
JLabel label =(JLabel)c;
label.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
label.setBackground(Color.lightGray);
label.setHorizontalTextPosition(SwingUtilities.CENTER);
label.setHorizontalAlignment(SwingUtilities.CENTER);
label.setText(value);
return label;
}
}
private class MyMouseAdapter extends MouseAdapter
{
#Override
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
int row = table.rowAtPoint(new Point(x,y));
int col = table.columnAtPoint(new Point(x,y));
if (col == 2)
{
String arr[] = new String[table.getColumnCount() - 1];
for (int i = 0 ; i < arr.length ; i++)
{
arr[i] = (String)table.getValueAt(row,i);
}
populateTextField(arr);
JOptionPane.showMessageDialog(TableRowEdit.this,dialogPanel,"Information",JOptionPane.INFORMATION_MESSAGE);
String[] values = new String[tf.length];
for (int i = 0 ; i < tf.length ; i++)
{
values[i] = tf[i].getText();
}
((MyModel)myModel).updateRow(row,values);//update row
}
}
}
private class MyModel extends AbstractTableModel
{
String[] columns = {
"Roll No.",
"Name",
"Action"
};
String[][] inData = {
{"1","Anthony Hopkins","Edit"},
{"2","James William","Edit"},
{"3","Mc. Donald","Edit"}
};
#Override
public void setValueAt(Object value, int row, int col)
{
inData[row][col] = (String)value;
fireTableCellUpdated(row,col);
}
#Override
public Object getValueAt(int row, int col)
{
return inData[row][col];
}
#Override
public int getColumnCount()
{
return columns.length;
}
#Override
public int getRowCount()
{
return inData.length;
}
#Override
public String getColumnName(int col)
{
return columns[col];
}
#Override
public boolean isCellEditable(int row ,int col)
{
return true;
}
//This method updates the Row of table
public void updateRow(int index,String[] values)
{
for (int i = 0 ; i < values.length ; i++)
{
setValueAt(values[i],index,i);
}
}
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
TableRowEdit td = new TableRowEdit();
td.prepareAndShowGUI();
}
});
}
}
UPDATE
Everything was fine with your original code. Keep the code as it was initially. The only problem was line userModel = new AllUser(); in method updateButtonActionPerformed. It was creating new object of AllUser instead of using the current one. So you should remove this line from updateButtonActionPerformed . and change the NewUserFrame_Edit constructor as follows:
public NewUserFrame_Edit(AllUser userModel/*Add this parameter*/,UserInformation userinf, int row) {
...
this.userModel = userModel;
jTextField1.setText(userinf.getFname().toString().trim());
jTextField2.setText(userinf.getLname().toString().trim());
if (userinf.getGender().equals("Male")) {
jRadioButton1.setSelected(true);
} else {
jRadioButton2.setSelected(true);
}
jTextField3.setText(userinf.getDate());
selectedrow = row;
setVisible(true);
}
change your as updateButtonActionPerformed follows:
private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {
//userModel = new AllUser();//Comment it.
userinf = new UserInformation();
userinf.setFname(jTextField1.getText());
userinf.setLname(jTextField2.getText());
userinf.setGender(gender);
userinf.setDate(jTextField3.getText());
userModel.setValueAt(userinf.getFname() , selectedrow, 1);
userModel.setValueAt(userinf.getLname() , selectedrow, 2);
userModel.setValueAt(userinf.getGender(), selectedrow , 3);
userModel.setValueAt(userinf.getDate() , selectedrow, 4);
userModel.updateFile(userModel.Udata);
NewUserFrame_Edit.this.dispose();
}
And changeeditUser(int row) method of class UserPage as follows:
public void editUser(int row)
{
UserInformation userInf = userModel.getSelectedMember(row);
NewUserFrame_Edit edit = new NewUserFrame_Edit(userModel,userInf, row);
}
Here is your updateFile methd:
public void updateFile(ArrayList<UserInformation> data) {
PrintWriter pw;
try {
pw = new PrintWriter(new FileWriter("AllUserRecords.txt"));
for (UserInformation userinf : data) {
String line = userinf.getID()
+ " " + userinf.getFname()
+ " " + userinf.getLname()
+ " " + userinf.getGender()
+ " " + userinf.getDate();
pw.println(line);
}
pw.close();
} catch (IOException ioe) {
}
}
Another way to implement changes through JTable is to use the code template below:
table.getModel().addTableModelListener(new TableModelListener(){
/**
* Called when table has been changed.
*/
#Override
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel) e.getSource();
String newdata = (String) model.getValueAt(row, column);
model.setValueAt(newdata, row, column);
// do your update with the newdata variable.
}
});
Here you can use the actual event to get the row and column of the cell that has been changed in the JTable variable.