I have created my JTable like this:
String[] columns = {"Country", "Continent", "Latitude", "Longitude"};
String[][] data = {{"A","B","C","D"}};
table = new JTable(data,columns);
JScrollPane spTable = new JScrollPane(table);
panel2.add(spTable);
Now I want to change the look of the table in such a way that rows will be exchanged with columns, meaning that the table will have 4 rows and 1 column. Could not find such function between member methods, is it possible? Thanks.
To do that, I would consider a custom TableModel which can handle a "toggled" state.
From your example, the result may be surprizing but this code shows you the general idea and allows you to swap rows and columns with a button.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public class TestTable {
private static class TogglingTableModel extends AbstractTableModel {
private boolean toggled = false;
private final Object[][] data;
private final Object[] columnNames;
public TogglingTableModel(Object[][] data, Object[] columnNames) {
this.columnNames = columnNames;
this.data = data;
normalizeData();
}
private void normalizeData() {
for (int i = 0; i < data.length; i++) {
Object[] o = data[i];
if (o.length < columnNames.length) {
data[i] = Arrays.copyOf(o, columnNames.length);
}
}
}
#Override
public String getColumnName(int column) {
if (toggled) {
Object valueAt;
if (column == 0) {
valueAt = columnNames[0];
} else {
valueAt = data[column - 1][0];
}
return valueAt != null ? valueAt.toString() : null;
} else {
Object object = columnNames[column];
return object != null ? object.toString() : null;
}
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
#Override
public int getColumnCount() {
if (toggled) {
return data.length + 1;
} else {
return columnNames.length;
}
}
#Override
public int getRowCount() {
if (toggled) {
return columnNames.length - 1;
} else {
return data.length;
}
}
#Override
public Object getValueAt(int row, int column) {
if (toggled) {
if (column == 0) {
return columnNames[row + 1];
} else {
return data[column - 1][row + 1];
}
} else {
return data[row][column];
}
}
#Override
public void setValueAt(Object aValue, int row, int column) {
if (toggled) {
if (column == 0) {
columnNames[row + 1] = aValue;
} else {
data[column - 1][row + 1] = aValue;
}
} else {
data[row][column] = aValue;
}
}
public boolean isToggled() {
return toggled;
}
public void toggle() {
toggled = !toggled;
fireTableStructureChanged();
}
}
private TogglingTableModel tableModel;
public TestTable() {
JFrame frame = new JFrame(TestTable.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String[] columns = { "Country", "Continent", "Latitude", "Longitude" };
String[][] data = { { "A" }, { "B" }, { "C" }, { "D" }, { "E" } };
tableModel = new TogglingTableModel(data, columns);
JTable table = new JTable(tableModel);
JPanel buttonPanel = new JPanel();
JButton togglingButton = new JButton("Toggle table");
togglingButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tableModel.toggle();
}
});
buttonPanel.add(togglingButton);
frame.add(new JScrollPane(table));
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestTable fs = new TestTable();
}
});
}
}
Related
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 );
Good day, guys. I would just like to ask, how can I set the value of the next column value? Here, I have the counter "counter" which adds the number of true boolean values in the sampleTable. What I want to do is to set the value of the data in the next column of the table, for the "total". the "total" data should be the counter value. What should I do about this?
private void tableTest(){
int nRow = sampleTable.getRowCount();
int nCol = sampleTable.getColumnCount();
int counter = 0;
Object[][] tableData = new Object[nRow][nCol];
for (int i = 0 ; i < nRow ; i++){
for (int j = 3 ; j < nCol ; j++){
tableData[i][j] = sampleTable.getValueAt(i,j);
System.out.println(tableData[i][j]);
if(tableData[i][j] != null && tableData[i][j].equals(true)){
counter++;
}
}
/* if(nCol == 7){
sampleTable.setValueAt(i, 7, counter);
}else{
tableData = new Object[nRow][nCol + 1];
sampleTable.setValueAt(i, 7, counter);
}*/
System.out.println(counter);
sampleTable.setValueAt(i,7,counter);
counter = 0;
}
}
Without more to go on, it's impossible to know 1. What you're trying to do and 2. What you might be doing wrong...
The following example is really, simple. What it does is allows you to is make changes to the table and then hit the "Update" button which then goes through and calculates the total for each row...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
public class TallyTableTest {
public static void main(String[] args) {
new TallyTableTest();
}
public TallyTableTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
final MyTableModel model = new MyTableModel();
loadData(model);
JTable table = new JTable(model);
JButton update = new JButton("Update");
update.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int row = 0; row < model.getRowCount(); row++) {
int counter = 0;
for (int col = 3; col < 7; col++) {
Object value = model.getValueAt(row, col);
if (value instanceof Boolean && (boolean)value) {
counter++;
}
}
model.setValueAt(counter, row, 7);
}
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.add(update, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public void loadData(MyTableModel model) throws IOException {
// Fill your model here
}
public static class MyTableModel extends AbstractTableModel {
protected static final String[] COLUMNS = new String[]{
"ID", "First Name", "Last Name", "1", "2", "3", "4", "total"
};
protected static final Class[] COLUMN_TYPES = new Class[]{
Integer.class, String.class, String.class,
Boolean.class, Boolean.class, Boolean.class, Boolean.class,
Integer.class
};
private List<Object[]> rows;
public MyTableModel() {
rows = new ArrayList<>(25);
}
public void addRow(Object[] data) {
rows.add(data);
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return COLUMNS.length;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return COLUMN_TYPES[columnIndex];
}
#Override
public String getColumnName(int column) {
return COLUMNS[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object[] row = rows.get(rowIndex);
return row[columnIndex];
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
Object[] row = rows.get(rowIndex);
row[columnIndex] = aValue;
fireTableCellUpdated(rowIndex, columnIndex);
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex >= 3 && columnIndex <= 6;
}
}
}
What the example does it updates the total in real time. What this means, is each time you change a column value for a row, it re-calculates that rows total and updates the model internally.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
public class TallyTableTest {
public static void main(String[] args) {
new TallyTableTest();
}
public TallyTableTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
final MyTableModel model = new MyTableModel();
loadData(model);
JTable table = new JTable(model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public void loadData(MyTableModel model) throws IOException {
// Fill your model here...
}
public static class MyTableModel extends AbstractTableModel {
protected static final String[] COLUMNS = new String[]{
"ID", "First Name", "Last Name", "1", "2", "3", "4", "total"
};
protected static final Class[] COLUMN_TYPES = new Class[]{
Integer.class, String.class, String.class,
Boolean.class, Boolean.class, Boolean.class, Boolean.class,
Integer.class
};
private List<Object[]> rows;
public MyTableModel() {
rows = new ArrayList<>(25);
}
public void addRow(Object[] data) {
rows.add(data);
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return COLUMNS.length;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return COLUMN_TYPES[columnIndex];
}
#Override
public String getColumnName(int column) {
return COLUMNS[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object[] row = rows.get(rowIndex);
return row[columnIndex];
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
Object[] row = rows.get(rowIndex);
row[columnIndex] = aValue;
int counter = 0;
for (int col = 3; col < 7; col++) {
Object value = row[col];
if (value instanceof Boolean && (boolean) value) {
counter++;
}
}
row[7] = counter;
fireTableCellUpdated(rowIndex, columnIndex);
fireTableCellUpdated(rowIndex, 7);
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex >= 3 && columnIndex <= 6;
}
}
}
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 need some help for my problem. I have a table with e.g. a double column and a string column. If the value in the double column is negativ, the string should be "negativ". And the other way if the value is positiv, the string should be "positiv".
The problem is now if I edit the double value in the jTable, the string should also be updated.
Update to my question, the actual code look like this:
But it doesn't work, because the string in the second column wont be updated after I edit the first column value. It only works when I start the program the first time.
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class ExampleRemoveAddRows extends JFrame {
private Object[] columnNames = {"Double", "positiv / negativ"};
private Object[][] data = {
{new Double(10.0), "positiv"},
{new Double(-10.0), "negativ"},
{new Double(20.0), "positiv"},
{new Double(-30.0), "negativ"}
};
private JTable table;
private DefaultTableModel model;
public ExampleRemoveAddRows() {
model = new DefaultTableModel(data, columnNames) {
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
#Override
public Object getValueAt(int row, int column) {
if (column == 1) {
double number = Double.parseDouble(this.getValueAt(row, 0).toString());
System.out.println(number);
System.out.println("good");
System.out.println((number < 0) ? "negativ" : "positiv");
return "C: "+ this.getValueAt(row, 0);//((number < 0) ? "negativ" : "positiv");
} else {
return super.getValueAt(row, column);
}
}
};
table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Thanks for your help.
Sam
I've revised your sscce to show the alternate approach suggested here. Note the alternate ways to get a Double constant. I've also re-factored the String constrants.
Addendum: In helpful comments, #kleopatra observes that querying the model directly will always produce the correct result, but a TableModelListener will only see changes to column 0, not column 1. The simple expedient is to make column 1 non-editable, as its value depends completely on column 0.
#Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
The first example below uses DefaultTableModel:
import javax.swing.*;
import javax.swing.table.*;
/** #see https://stackoverflow.com/a/13628183/230513 */
public class ExampleRemoveAddRows extends JFrame {
public static final String NEGATIVE = "negativ";
public static final String POSITIVE = "positiv";
private Object[] columnNames = {"Double", POSITIVE + " / " + NEGATIVE};
private Object[][] data = {
{10d, null},
{-10.0, null},
{Double.valueOf(30), null},
{Double.valueOf("-30"), null}
};
private JTable table;
private DefaultTableModel model;
public ExampleRemoveAddRows() {
model = new DefaultTableModel(data, columnNames) {
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
#Override
public Object getValueAt(int row, int col) {
if (col == 1) {
double number = (Double) this.getValueAt(row, 0);
return (number < 0) ? NEGATIVE : POSITIVE;
} else {
return super.getValueAt(row, col);
}
}
#Override
public void setValueAt(Object aValue, int row, int col) {
super.setValueAt(aValue, row, col);
fireTableCellUpdated(row, 1); // may have changed
}
};
table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
This variation extends AbstractTableModel:
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
/**
* #see https://stackoverflow.com/a/13628183/230513
*/
public class ExampleRemoveAddRows extends JFrame {
public static final String NEGATIVE = "negativ";
public static final String POSITIVE = "positiv";
public ExampleRemoveAddRows() {
DoubleModel model = new DoubleModel();
model.add(10.1);
model.add(-10.2);
model.add(Double.valueOf(30.1));
model.add(Double.valueOf("-30.2"));
JTable table = new JTable(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private class DoubleModel extends AbstractTableModel {
List<Double> data = new ArrayList<Double>();
public void add(Double d) {
data.add(d);
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public String getColumnName(int col) {
if (col == 0) {
return "Double";
} else {
return POSITIVE + " / " + NEGATIVE;
}
}
#Override
public Class<?> getColumnClass(int col) {
if (col == 0) {
return Double.class;
} else {
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
#Override
public Object getValueAt(int row, int col) {
if (col == 0) {
return data.get(row);
} else {
double number = (Double) this.getValueAt(row, 0);
return (number < 0) ? NEGATIVE : POSITIVE;
}
}
#Override
public void setValueAt(Object aValue, int row, int col) {
if (col == 0) {
data.set(row, (Double) aValue);
fireTableRowsUpdated(row, row);
}
}
}
}
You do indeed have access to the TableModel, if I'm not mistaken, through TableModelEvent.getSource().
Just to provide a basic example (mostly because the one sentance answer hardly seems like much of an answer):
TableModel model = (TableModel)te.getSource();
Double number = model.getValueAt(te.firstRow, 0);
model.setValueAt(((number < 0) ? "negativ":"positiv"), te.firstRow, 1);
I want to gray non-editable cell in JTable.
I'm using such TableCellRenderer:
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellRenderer(new GrayableCheckboxCellRenderer());
public class GrayableCheckboxCellRenderer extends JCheckBox implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int vRowIndex, int vColIndex) {
boolean editable = isEditable(vRowIndex, vColIndex);
setBackground(editable ? UIManager.getColor("Label.background") : Color.LIGHT_GRAY);
setSelected((Boolean) value);
if (isSelected) {
// TODO: cell (and perhaps other cells) are selected, need to highlight it
}
return this;
}
// perfomance
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {}
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
public void revalidate() {}
public void validate() {}
}
This works but with one annoying artefact:
Initially "checkbox" is "left-arranged", when I press left mouse button it moves to "center-arranged" and when I release mouse button it moves back to "left-arranged".
How to avoid such annoying artefact and probably there are better simpler solution for my problem?
Return an instance of GrayableCheckboxCellRenderer in a TableCellEditor.
Addendum: Aesthetically, you may want to condition the renderer's and editor's colors based on the defaults provided by the current Look & Feel, for example:
Color hilite = UIManager.getColor("Table.selectionBackground");
simpliest way by using preparedRenderer
import java.awt.*;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class Forum {
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 void addComponentsToPane(Container pane) {
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);
boolean type2 = (Boolean) getModel().isCellEditable(row, column);
comp.setForeground(Color.black);
if ((type) && (!type1)) {
comp.setBackground(Color.yellow);
} else if ((!type) && (type1)) {
comp.setBackground(Color.orange);
} else if ((!type) || (!type1)) {
comp.setBackground(Color.red);
//} else if ((!type2)) {
//comp.setForeground(Color.red);
//comp.setBackground(Color.magenta);
} else {
comp.setBackground(row % 2 == 0 ? getBackground() : getBackground().darker());
}
dialogTable.convertRowIndexToView(0);
} else {
comp.setForeground(Color.blue);
comp.setBackground(Color.lightGray);
}
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);
fatherCenter = new JPanel();
fatherCenter.setLayout(new BorderLayout(10, 10));
fatherCenter.add(tableScroll, BorderLayout.CENTER);
pane.add(fatherCenter);
}
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("Cell " + tme.getFirstRow() + ", "
+ tme.getColumn() + " changed. The new value: "
+ tableModel.getValueAt(tme.getFirstRow(),
tme.getColumn()));
}
}
});
}
private void createAndShowGUI() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(10, 10));
addComponentsToPane(frame.getContentPane());
addData();
frame.setLocation(150, 150);
frame.setPreferredSize(new Dimension(400, 646));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
Forum osFrame = new Forum();
}
public Forum() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
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};
myTableModel() {
this.colNames = new Vector<String>();
this.data = new Vector<Vector<Object>>();
}
myTableModel(Vector<String> colnames) {
this.colNames = colnames;
this.data = new Vector<Vector<Object>>();
}
public void resetTable() {
this.colNames.removeAllElements();
this.data.removeAllElements();
}
public void setColumnNames(Vector<String> colNames) {
this.colNames = colNames;
this.fireTableStructureChanged();
}
public void addRow(Vector<Object> data) {
this.data.add(data);
this.fireTableDataChanged();
this.fireTableStructureChanged();
}
public void removeRowAt(int row) {
this.data.removeElementAt(row);
this.fireTableDataChanged();
}
#Override
public int getColumnCount() {
return this.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 this.colNames.get(colNum);
}
#Override
public int getRowCount() {
return this.data.size();
}
#Override
public Object getValueAt(int row, int col) {
Vector<Object> value = this.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) {
this._columnsVisible[index] = visible;
this.fireTableStructureChanged();
}
}
}
Just explicitly setting the alignment in the 'getTableCellRendererComponent()' method solves the problem. Add the below line before returning from the method.
setHorizontalAlignment(SwingConstants.CENTER);