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;
}
}
}
Related
Good day!
There is a problem in downloaded program. You can copy a row by clicking on it by right mouse button, but after that when you change data in one cell data will be changed in every cell in column. Please, help me to understand, what I've missed.
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public class Main extends JFrame{
JMenuItem obrc;
JTable table;
DataModel tm;
JScrollPane scrollTable;
Main() {
super("Example JTable");
Container c = getContentPane();
ArrayList<String> columnNames = new ArrayList<String>();
columnNames.add("Type"); columnNames.add("Sort"); columnNames.add("Thickness"); columnNames.add("Width");
tm = new DataModel(columnNames);
table = new JTable(tm);
c.add(new JScrollPane(table), BorderLayout.CENTER);
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
table.getColumnModel().getColumn(0).setPreferredWidth(40);
table.getColumnModel().getColumn(1).setPreferredWidth(40);
table.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent event) {
if (SwingUtilities.isRightMouseButton(event)) {
JPopupMenu obrcd = new JPopupMenu();
obrc = new JMenuItem("Copy");
obrc.addActionListener(new MenuListener());
obrcd.add(obrc);
obrcd.show(c, event.getX(), event.getY());
}
}
});
}
public class MenuListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
int[] nums = table.getSelectedRows();
if (nums.length != 0) {
if (e.getSource() == obrc) {
ArrayList<Object[]> list = tm.getRows(nums);
tm.addRows(list);
}
else JOptionPane.showMessageDialog(null,
"Select at least one row", "Warning", JOptionPane.ERROR_MESSAGE);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
class DataModel extends AbstractTableModel{
ArrayList<Object[]> data = new ArrayList<Object[]>();
ArrayList<String> columnNames = new ArrayList<String>();
public DataModel(ArrayList<String> cNames){
super();
columnNames = cNames;
Object[] dat = new Object[4];
dat[0] = "board";
dat[1] = "1";
dat[2] = "25";
dat[3] = "150";
data.add(dat);
}
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return true;
}
public Object getValueAt(int rowIndex, int columnIndex){
Object[] row = data.get(rowIndex);
return row[columnIndex];
};
public void setValueAt(Object newValue, int rowIndex, int columnIndex){
data.get(rowIndex)[columnIndex] = newValue;
fireTableDataChanged();
}
public int getRowCount()
{
return data.size();
};
public int getColumnCount()
{
return columnNames.size();
};
public String getColumnName(int column)
{
return columnNames.get(column);
}
public ArrayList<Object[]> getRows(int[] nums) {
ArrayList<Object[]> newdata = new ArrayList<Object[]>();
for (int i = 0; i < nums.length; i++) {
newdata.add(data.get(nums[i]));
}
return newdata;
}
public void addRows (ArrayList<Object[]> rows) {
for (int i = 0; i < rows.size(); i++) data.add(rows.get(i));
fireTableDataChanged();
}
}
}
Problem when you are adding new rows
public void addRows (ArrayList<Object[]> rows) {
for (int i = 0; i < rows.size(); i++) data.add(rows.get(i));
fireTableDataChanged();
}
Your copied row(s) will point to same object(s) with selected row(s). You need clone to new object:
public void addRows (ArrayList<Object[]> rows) {
for (int i = 0; i < rows.size(); i++) {
Object[] clone = rows.get(i).clone();
data.add(clone);
}
fireTableDataChanged();
}
I would like to populate a JTable during runtime with many rows (lets say 10000). But all my attempts are very poor and inefficient.
Starting point is the addData method which gets a List of Objects representing a row. I tried to fill the table via a SwingWorker but this only works for small data for me.
Another attempt was setting the data directly without using any kind of thread, but this is also very slow, at least the UI isn't blocked like its the case with the SwingWorker.
So how do you do this is general? The table should be filled row by row or chunkwise but not all by one and the vertical scrollbar should be scrollable meanwhile.
My TableModel:
public class MyTableModel extends AbstractTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
String[] columnNames;
public Map<Long, ErrorMessage> data = new LinkedHashMap<Long, ErrorMessage>();
public MyTableModel(String[] header) {
columnNames = header;
}
public String getColumnName(int col) {
return columnNames[col].toString();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
.
.
return value;
}
public void addRow(long id, MyDataObject o) {
data.put(id, m);
fireTableRowsInserted(0,nqm_messages.size()-1);
}
}
SwingWorker implementation:
class TableSwingWorker extends SwingWorker<MyTableModel, MyDataObject> {
private final MyTableModel tableModel;
List<MyDataObject> messages;
public TableSwingWorker(MyTableModel tableModel, List<MyDataObject> dataList) {
this.tableModel = tableModel;
this.messages = new LinkedList<MyDataObject>(mm);
}
#Override
protected MyTableModel doInBackground() throws Exception {
for(MyDataObject s : messages) {
publish(s);
}
return tableModel;
}
#Override
protected void process(List<MyDataObject> chunks) {
for(MyDataObject row : chunks){
Long l = Long.parseLong(row.getId());
tableModel.addRow(l, row);
}
}
}
Add Objects to JTable:
public void addData(List<MyDataObject> o) {
MyTableModel m = (MyTableModel)table.getModel();
(new TableSwingWorker(m,o)).execute();
//for(int i=0; i < mm.size();i++) {
// long l = Long.parseLong(mm.get(i).getId());
// m.addRow(l, mm.get(i));
//}
}
So, a number of things have being identified from the comments...
You need to correctly fire the row inserted method, indicating only those rows that have being added and where they have being updated. This very important, as the the table has being optimised for speed
You should provide batch add method for your table model, allowing you to more easily add multiple rows in a single or as few steps as possible
You should have the SwingWorker periodically sleep or yield, to allow it time to publish the results.
So, in this example, I'm adding 1, 000, 000 rows. In my test it took slightly under 1 second...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class TestTableLoad01 {
public static void main(String[] args) {
new TestTableLoad01();
}
public TestTableLoad01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
MyTableModel model = new MyTableModel();
JTable table = new JTable(model);
table.setDefaultRenderer(Date.class, new TimeCellRenderer());
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);
TableSwingWorker worker = new TableSwingWorker(model);
worker.execute();
}
});
}
public class TimeCellRenderer extends DefaultTableCellRenderer {
private DateFormat df;
public TimeCellRenderer() {
df = new SimpleDateFormat("HH:mm:ss");
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Date) {
value = df.format(value);
}
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return this;
}
}
public class MyTableModel extends AbstractTableModel {
private String[] columnNames = new String[]{"Date", "Row"};
private List<RowData> data;
public MyTableModel() {
data = new ArrayList<>(25);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Date.class : Integer.class;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
RowData value = data.get(row);
return col == 0 ? value.getDate() : value.getRow();
}
public void addRow(RowData value) {
int rowCount = getRowCount();
data.add(value);
fireTableRowsInserted(rowCount, rowCount);
}
public void addRows(RowData... value) {
addRows(Arrays.asList(value));
}
private void addRows(List<RowData> rows) {
int rowCount = getRowCount();
data.addAll(rows);
fireTableRowsInserted(rowCount, getRowCount() - 1);
}
}
public class RowData {
private Date date;
private int row;
public RowData(int row) {
this.date = new Date();
this.row = row;
}
public Date getDate() {
return date;
}
public int getRow() {
return row;
}
}
public class TableSwingWorker extends SwingWorker<MyTableModel, RowData> {
private final MyTableModel tableModel;
public TableSwingWorker(MyTableModel tableModel) {
this.tableModel = tableModel;
}
#Override
protected MyTableModel doInBackground() throws Exception {
// This is a deliberate pause to allow the UI time to render
Thread.sleep(2000);
System.out.println("Start polulating");
for (int index = 0; index < 1000000; index++) {
RowData data = new RowData(index);
publish(data);
Thread.yield();
}
return tableModel;
}
#Override
protected void process(List<RowData> chunks) {
System.out.println("Adding " + chunks.size() + " rows");
tableModel.addRows(chunks);
}
}
}
I am facing two problems with my table. I managed to add a header to the rows. However, they are not resizing themselves even though I am using headerTable.setAutoResizeModeJTable.AUTO_RESIZE_ALL_COLUMNS);. Furthermore, my columnNames are not displayed even though I set them in the Table model.
Here is a short sample program:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.RowSorterListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class JTableRowHeader {
private JFrame frame = new JFrame("JTable RowHeader");
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel model;
private TableRowSorter<TableModel> sorter;
private JTable headerTable;
public JTableRowHeader() {
table = new JTable(5, 10);
for (int i = 0; i < table.getRowCount(); i++) {
System.out.println(i);
for (int a = 0; a < table.getColumnCount(); a++) {
System.out.println(a);
table.setValueAt(a, i, a);
}
}
sorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowSorter(sorter);
model = new DefaultTableModel() {
/**
* UUID
*/
private static final long serialVersionUID = 2797195270050411045L;
private String[] columnNames = {"test1", "test2", "test3", "test3", "test5"};
#Override
public int getColumnCount() {
return 1;
}
#Override
public boolean isCellEditable(int row, int col) {
return false;
}
#Override
public String getColumnName(int index) {
return columnNames[index];
}
#Override
public int getRowCount() {
return table.getRowCount();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return String.class;
default:
return super.getColumnClass(colNum);
}
}
};
//set table headers
headerTable = new JTable(model);
headerTable.setValueAt("Costs", 0, 0);
headerTable.setValueAt("Product", 1, 0);
headerTable.setValueAt("Table", 2, 0);
headerTable.setValueAt("Risk", 3, 0);
headerTable.setValueAt("Equity", 4, 0);
headerTable.setShowGrid(true);
headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
headerTable.setPreferredScrollableViewportSize(new Dimension(50, 0));
headerTable.getColumnModel().getColumn(0).setPreferredWidth(50);
headerTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable x, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
boolean selected = table.getSelectionModel().isSelectedIndex(row);
Component component = table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, false, false, -1, -2);
((JLabel) component).setHorizontalAlignment(SwingConstants.CENTER);
if (selected) {
component.setFont(component.getFont().deriveFont(Font.BOLD));
component.setForeground(Color.red);
} else {
component.setFont(component.getFont().deriveFont(Font.PLAIN));
}
return component;
}
});
table.getRowSorter().addRowSorterListener(new RowSorterListener() {
#Override
public void sorterChanged(RowSorterEvent e) {
model.fireTableDataChanged();
}
});
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
});
scrollPane = new JScrollPane(table);
scrollPane.setRowHeaderView(headerTable);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
//e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JTableRowHeader TestTableRowHeader = new JTableRowHeader();
}
});
}
}
I really appreciate your help!
UPDATE
When putting for my table headers something like that inside:
headerTable = new JTable(model);
headerTable.setValueAt("Costs and Sales", 0, 0);
headerTable.setValueAt("Product", 1, 0);
headerTable.setValueAt("Table", 2, 0);
headerTable.setValueAt("Risk", 3, 0);
headerTable.setValueAt("Equity in million", 4, 0);
You can see they are cut of:
UPDATE 2
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.RowSorterListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class JTableRowHeader {
private JFrame frame = new JFrame("JTable RowHeader");
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel model;
private TableRowSorter<TableModel> sorter;
private JTable headerTable;
public JTableRowHeader() {
table = new JTable(5, 10);
for (int i = 0; i < table.getRowCount(); i++) {
System.out.println(i);
for (int a = 0; a < table.getColumnCount(); a++) {
System.out.println(a);
table.setValueAt(a, i, a);
}
}
sorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowSorter(sorter);
model = new DefaultTableModel() {
/**
* UUID
*/
private static final long serialVersionUID = 2797195270050411045L;
private String[] columnNames = {"test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10"};
#Override
public int getColumnCount() {
return 1;
}
#Override
public boolean isCellEditable(int row, int col) {
return false;
}
#Override
public String getColumnName(int index) {
return columnNames[index];
}
#Override
public int getRowCount() {
return table.getRowCount();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return String.class;
default:
return super.getColumnClass(colNum);
}
}
};
//set table headers
headerTable = new JTable(model);
headerTable.setValueAt("Costs and Sales", 0, 0);
headerTable.setValueAt("Product", 1, 0);
headerTable.setValueAt("Table 234", 2, 0);
headerTable.setValueAt("Risk and Equity", 3, 0);
headerTable.setValueAt("Equity in million", 4, 0);
headerTable.setShowGrid(false);
headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
headerTable.setPreferredScrollableViewportSize(new Dimension(50, 0));
headerTable.getColumnModel().getColumn(0).setPreferredWidth(50);
headerTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable x, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
boolean selected = table.getSelectionModel().isSelectedIndex(row);
Component component = table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, false, false, -1, -2);
((JLabel) component).setHorizontalAlignment(SwingConstants.CENTER);
if (selected) {
component.setFont(component.getFont().deriveFont(Font.BOLD));
component.setForeground(Color.red);
} else {
component.setFont(component.getFont().deriveFont(Font.PLAIN));
}
return component;
}
});
table.getRowSorter().addRowSorterListener(new RowSorterListener() {
#Override
public void sorterChanged(RowSorterEvent e) {
model.fireTableDataChanged();
}
});
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
});
scrollPane = new JScrollPane(table);
scrollPane.setRowHeaderView(headerTable);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
//e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JTableRowHeader TestTableRowHeader = new JTableRowHeader();
}
});
}
}
You can see that my columnNames stay the same, when adding enough columns. Furthermore, my header table is not resizable.
I appreciate your reply!
Furthermore, my columnNames are not displayed even though I set them
in the Table model.
???
However, they are not resizing themselves even though I am using
headerTable.setAutoResizeModeJTable.AUTO_RESIZE_ALL_COLUMNS);.
??? (but you haven't access to RowHeader from MouseEvents, never seen good code here for)
.
.
changed only table.setValueAt(a , i, a); to table.setValueAt(a + i, i, a);
EDIT
from code (fill all values in XxxTableModel, setting for TableColumnModel is last of property )
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.UIManager.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class JTableRowHeader {
private JFrame frame = new JFrame("JTable RowHeader");
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel dataModel;
private DefaultTableModel model;
private TableRowSorter<TableModel> sorter;
private JTable headerTable;
private String[] columnNames = {"test1", "test2", "test3", "test3"};
public JTableRowHeader() {
table = new JTable(4, 4);
dataModel = (DefaultTableModel) table.getModel();
for (int i = 0; i < dataModel.getRowCount(); i++) {
for (int ii = 0; ii < dataModel.getRowCount(); ii++) {
dataModel.setValueAt(i + ii, i, ii);
}
}
TableColumnModel tcm = table.getColumnModel();
tcm.getColumn(0).setHeaderValue(columnNames[0]);
tcm.getColumn(1).setHeaderValue(columnNames[1]);
tcm.getColumn(2).setHeaderValue(columnNames[2]);
tcm.getColumn(3).setHeaderValue(columnNames[3]);
sorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowSorter(sorter);
model = new DefaultTableModel() {
private static final long serialVersionUID = 1L;
#Override
public int getColumnCount() {
return 1;
}
#Override
public boolean isCellEditable(int row, int col) {
return false;
}
#Override
public int getRowCount() {
return table.getRowCount();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return String.class;
default:
return super.getColumnClass(colNum);
}
}
};
headerTable = new JTable(model);
for (int i = 0; i < table.getRowCount(); i++) {
headerTable.setValueAt("Row " + (i + 1), i, 0);
}
headerTable.setShowGrid(false);
headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
headerTable.setPreferredScrollableViewportSize(new Dimension(50, 0));
headerTable.getColumnModel().getColumn(0).setPreferredWidth(50);
headerTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable x, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
boolean selected = table.getSelectionModel().isSelectedIndex(row);
Component component = table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, false, false, -1, -2);
((JLabel) component).setHorizontalAlignment(SwingConstants.CENTER);
if (selected) {
component.setFont(component.getFont().deriveFont(Font.BOLD));
component.setForeground(Color.red);
} else {
component.setFont(component.getFont().deriveFont(Font.PLAIN));
}
return component;
}
});
table.getRowSorter().addRowSorterListener(new RowSorterListener() {
#Override
public void sorterChanged(RowSorterEvent e) {
model.fireTableDataChanged();
}
});
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
});
scrollPane = new JScrollPane(table);
scrollPane.setRowHeaderView(headerTable);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(scrollPane);
frame.add(new JButton(new AbstractAction("Toggle filter") {
private static final long serialVersionUID = 1L;
private RowFilter<TableModel, Object> filter = new RowFilter<TableModel, Object>() {
#Override
public boolean include(javax.swing.RowFilter.Entry<? extends TableModel, ? extends Object> entry) {
return ((Number) entry.getValue(0)).intValue() % 2 == 0;
}
};
#Override
public void actionPerformed(ActionEvent e) {
if (sorter.getRowFilter() != null) {
sorter.setRowFilter(null);
} else {
sorter.setRowFilter(filter);
}
}
}), BorderLayout.SOUTH);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
try {// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (info.getName().equals("Nimbus")) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
//e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JTableRowHeader TestTableRowHeader = new JTableRowHeader();
}
});
}
}
I would like to populate a JTable during runtime with many rows (lets say 10000). But all my attempts are very poor and inefficient.
Starting point is the addData method which gets a List of Objects representing a row. I tried to fill the table via a SwingWorker but this only works for small data for me.
Another attempt was setting the data directly without using any kind of thread, but this is also very slow, at least the UI isn't blocked like its the case with the SwingWorker.
So how do you do this is general? The table should be filled row by row or chunkwise but not all by one and the vertical scrollbar should be scrollable meanwhile.
My TableModel:
public class MyTableModel extends AbstractTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
String[] columnNames;
public Map<Long, ErrorMessage> data = new LinkedHashMap<Long, ErrorMessage>();
public MyTableModel(String[] header) {
columnNames = header;
}
public String getColumnName(int col) {
return columnNames[col].toString();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
.
.
return value;
}
public void addRow(long id, MyDataObject o) {
data.put(id, m);
fireTableRowsInserted(0,nqm_messages.size()-1);
}
}
SwingWorker implementation:
class TableSwingWorker extends SwingWorker<MyTableModel, MyDataObject> {
private final MyTableModel tableModel;
List<MyDataObject> messages;
public TableSwingWorker(MyTableModel tableModel, List<MyDataObject> dataList) {
this.tableModel = tableModel;
this.messages = new LinkedList<MyDataObject>(mm);
}
#Override
protected MyTableModel doInBackground() throws Exception {
for(MyDataObject s : messages) {
publish(s);
}
return tableModel;
}
#Override
protected void process(List<MyDataObject> chunks) {
for(MyDataObject row : chunks){
Long l = Long.parseLong(row.getId());
tableModel.addRow(l, row);
}
}
}
Add Objects to JTable:
public void addData(List<MyDataObject> o) {
MyTableModel m = (MyTableModel)table.getModel();
(new TableSwingWorker(m,o)).execute();
//for(int i=0; i < mm.size();i++) {
// long l = Long.parseLong(mm.get(i).getId());
// m.addRow(l, mm.get(i));
//}
}
So, a number of things have being identified from the comments...
You need to correctly fire the row inserted method, indicating only those rows that have being added and where they have being updated. This very important, as the the table has being optimised for speed
You should provide batch add method for your table model, allowing you to more easily add multiple rows in a single or as few steps as possible
You should have the SwingWorker periodically sleep or yield, to allow it time to publish the results.
So, in this example, I'm adding 1, 000, 000 rows. In my test it took slightly under 1 second...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class TestTableLoad01 {
public static void main(String[] args) {
new TestTableLoad01();
}
public TestTableLoad01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
MyTableModel model = new MyTableModel();
JTable table = new JTable(model);
table.setDefaultRenderer(Date.class, new TimeCellRenderer());
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);
TableSwingWorker worker = new TableSwingWorker(model);
worker.execute();
}
});
}
public class TimeCellRenderer extends DefaultTableCellRenderer {
private DateFormat df;
public TimeCellRenderer() {
df = new SimpleDateFormat("HH:mm:ss");
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Date) {
value = df.format(value);
}
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return this;
}
}
public class MyTableModel extends AbstractTableModel {
private String[] columnNames = new String[]{"Date", "Row"};
private List<RowData> data;
public MyTableModel() {
data = new ArrayList<>(25);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Date.class : Integer.class;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
RowData value = data.get(row);
return col == 0 ? value.getDate() : value.getRow();
}
public void addRow(RowData value) {
int rowCount = getRowCount();
data.add(value);
fireTableRowsInserted(rowCount, rowCount);
}
public void addRows(RowData... value) {
addRows(Arrays.asList(value));
}
private void addRows(List<RowData> rows) {
int rowCount = getRowCount();
data.addAll(rows);
fireTableRowsInserted(rowCount, getRowCount() - 1);
}
}
public class RowData {
private Date date;
private int row;
public RowData(int row) {
this.date = new Date();
this.row = row;
}
public Date getDate() {
return date;
}
public int getRow() {
return row;
}
}
public class TableSwingWorker extends SwingWorker<MyTableModel, RowData> {
private final MyTableModel tableModel;
public TableSwingWorker(MyTableModel tableModel) {
this.tableModel = tableModel;
}
#Override
protected MyTableModel doInBackground() throws Exception {
// This is a deliberate pause to allow the UI time to render
Thread.sleep(2000);
System.out.println("Start polulating");
for (int index = 0; index < 1000000; index++) {
RowData data = new RowData(index);
publish(data);
Thread.yield();
}
return tableModel;
}
#Override
protected void process(List<RowData> chunks) {
System.out.println("Adding " + chunks.size() + " rows");
tableModel.addRows(chunks);
}
}
}
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();
}
});
}
}