I know spacing JTable cells are pretty straight forward as shown below;
int gapWidth = 10;
int gapHeight = 5;
table.setIntercellSpacing(new Dimension(gapWidth, gapHeight));
Spacing like this doesn't seems to affect the tables header. Is there a way to space the header with the same dimension?
Easiest way could be to set EmptyBorders to the JTableHeader inside the TableCellRenderer
The code above does my spacing, but the alignment of header and the actual row cell values looks slighly off - as a result of spacing only placed on cells but not the header.
I added a SSCCE (3mins 27seconds inc. uploading here)
from code
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class IntercellSpacingTableHeader {
private JFrame frame = new JFrame("Table Demo");
private String[] columnNames = {"String", "Integer", "Float", "Double"};
private Object[][] data = {
{"aaa", new Integer(12), new Float(12.15), new Double(100.05)},
{"bbb", new Integer(5), new Float(7.154), new Double(6.1555)},
{"CCC", new Integer(92), new Float(0.1135), new Double(3.1455)},
{"ddd", new Integer(12), new Float(31.15), new Double(10.05)},
{"eee", new Integer(5), new Float(5.154), new Double(16.1555)},
{"fff", new Integer(92), new Float(4.1135), new Double(31.1455)}};
private TableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
private JTable table = new JTable(model);
public IntercellSpacingTableHeader() {
int gapWidth = 10;
int gapHeight = 5;
table.setIntercellSpacing(new Dimension(gapWidth, gapHeight));
table.setRowHeight(20);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scroll = new JScrollPane(table);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scroll);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new IntercellSpacingTableHeader();
}
});
}
}
Related
It downloads data from ThingSpeak and show in jtable. I create a 'refresh' button which will download latest data and show in existing gui table.
get the latest data...work
store in List/arrays...work
update the jtable...Nop
I have tried fireTableDataChanged, setModel, revalidate, invalidate and repaint but still doesn't update the table. What am I missing?
public class Menu{
protected static List<String> list_name = new ArrayList<>();
// .....(10 more like above)
private JFrame frame = new JFrame("Temp");
private List<String[]> records_data = new ArrayList<String[]>();
private JTable table;
private DefaultTableModel model;
private String[][] data2 = new String[list_channel_ID.size()][11];
String[] columnNames_records = {"Location"}; // skip 10 more items
protected Menu(){
// Jframe > Jtabbedpane > jtable( I skip all these codes)
//- Table(Records)
for(int i = 0; i < list_channel_ID.size(); i++){
records_data.add(new String[]{ list_name.get(i) });} // Load data from List to jtable require format, skip 10 items
//table = new JTable(records_data.toArray(new Object[][] {}), columnNames_records); // when 'model' is not use
model = new DefaultTableModel(records_data.toArray(new Object[][] {}), columnNames_records);
//model = new DefaultTableModel(data2, columnNames);
table = new JTable(model);
JMenuItem process_refresh = new JMenuItem("Refresh");
process_refresh.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Update the list
for(int i = 0; i < list_channel_ID.size(); i++){
records_data.add(new String[]{ list_name.get(i) }); // load from list again, skiped 10 item
}
model = new DefaultTableModel(records_data.toArray(new Object[][] {}), columnNames_records);
model.fireTableDataChanged();
//table.setModel(model);
table.revalidate();
//table.invalidate();
table.repaint();
}
});
}
}
Problem solve, I forgot to clear the list 'records_data' :|
I will leave it here if someone face the same problem and mind blown for 2 days like me
Working code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.lang.String;
import java.util.List;
import java.util.ArrayList;
public class Menu{
protected static List<String> list_name = List.of("AAA", "BBB", "CCC");
// .....(10 more like above)
private JFrame frame = new JFrame("Temp");
private List<String[]> records_data = new ArrayList<String[]>();
private List<String[]> result_data = new ArrayList<String[]>();
private JTable table, table2, table3;
private DefaultTableModel model;
private String[][] data2 = new String[3][11];
String[] columnNames_records = {"item A", "item B", "item C"}; // 10 more items
protected Menu(){
frame.setSize(1000, 600);
frame.setLayout(new GridLayout(2, 1));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//- Back Panel
JPanel panel = new JPanel(null);
frame.add(panel);
JPanel tab_panel = new JPanel(new GridLayout());
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.setBounds(5, 100, 975, 500);
tabbedPane.add("Records", tab_panel);
frame.add(tabbedPane);
//- Table(Records)
for(int i = 0; i < 3; i++){
records_data.add(new String[]{ list_name.get(i) });
} // Load data from List to jtable require format, skiped 10 item
//table = new JTable(records_data.toArray(new Object[][] {}), columnNames_records);
model = new DefaultTableModel(records_data.toArray(new Object[][] {}), columnNames_records);
//model = new DefaultTableModel(data2, columnNames);
table = new JTable(model);
table.setRowHeight(20);
//- ScrollPane, allow scrolling if table too long
JScrollPane scrollPane = new JScrollPane(table);
tab_panel.add(scrollPane);
// Menu bar
JMenu menu_process = new JMenu("Process");
JMenuItem process_refresh = new JMenuItem("Refresh");
process_refresh.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
records_data.clear();
list_name = List.of("DDD", "EEE", "FFF"); // Update the list, hardcode for now
//list_name.add("KKK");
for(int i = 0; i < 3; i++){
records_data.add(new String[]{ list_name.get(i) }); // load from list again, skiped 10 item
}
model = new DefaultTableModel(records_data.toArray(new Object[][] {}), columnNames_records);
//model.fireTableDataChanged();
table.setModel(model);
//table.revalidate();
//table.invalidate();
//table.repaint();
}
});
menu_process.add(process_refresh);
JMenuBar menu_bar = new JMenuBar();
menu_bar.add(menu_process);
frame.setJMenuBar(menu_bar);
frame.setVisible(true);
}
public static void main(String[ ] args) {
new Menu();
}
}
The code below takes data from a text file delimited by "|" and displays it in a JTable. When I run it on the JFrame itself it does work. However I cannot figure out how to move it to another class for itself and make it become a method such as public void viewUser(){}, then call it from the frame on click of a button.
public void viewUser(){
File file = new File("user.dat");
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
DefaultTableModel model = (DefaultTableModel)jTable1.getModel();
Object[] lines = br.lines().toArray();
for (Object line : lines) {
String[] row = line.toString().split("\\|");
model.addRow(row);
}
} catch (IOException ex) {
Logger.getLogger(UserManagement.class.getName()).log(Level.SEVERE, null, ex);
}
You are getting this wrong conceptually: a model by itself is meaningless. It needs to be connected to a table in order to show its content.
The code you are showing is creating and filling a new table model. Then that model and all the information is thrown away. Reading data into an object is pointless, when that object isn't made available for further usage!
You might simply change the return type from void to DefaultTableModel and return the model object in the end. And then you can use that pre-filled model for any JTable!
Run this mcve and see if it mocks what you want to do:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class TablePane extends JPanel {
private final JTable table;
public TablePane() {
super(new GridLayout(1,0));
String[] columnNames = {"Name", "Age" };
Object[][] data = {
{"Kathy", new Integer(35)},
{"John", new Integer(63)},
{"Sue", new Integer(28)},
{"Joe", new Integer(70)}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table = new JTable(model);
table.setPreferredScrollableViewportSize(new Dimension(300, 100));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
void refresh() {
new Updater(table).getNewData();
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TablePane tablePane = new TablePane();
frame.add(tablePane);
JButton button = new JButton("Change data");
button.addActionListener(e -> tablePane.refresh());
frame.add(button, BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
class Updater {
private DefaultTableModel model;
Object[][] testData = {
{"Bon", new Integer(15)},
{"Anna", new Integer(31)},
{"Dan", new Integer(82)},
{"Jane", new Integer(20)},
};
public Updater(JTable table) {
model = (DefaultTableModel)table.getModel();
}
void getNewData(){
//if you want to clear data : model.getDataVector().clear();
for (Object[] row : testData) {
model.addRow(row);
}
}
}
As commented by Andrew Thomson mcve with hard coded data is essential.
public static void table2() {
Object num[] = new Object[1];
for (int q = 0; q < MyDto.userList.size(); q++) {
try {
//ImageIcon i2 = new ImageIcon(new ImageIcon(MyDto.userList.get(q).getMyImg()).getImage()
// .getScaledInstance(150, 120, Image.SCALE_SMOOTH));
ImageIcon i2 = new ImageIcon("/Users/junseok/Desktop/1.png");
JLabel lbImage1 = new JLabel(i2);
lbImage1.setIcon(i2);
num[0] = lbImage1;
model2.addRow(num);
System.out.println(num[0].toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
why doesnt show image? why write only toString()??
why write only toString()??
The default renderer just invokes the toString() method of the object in the TableModel.
why doesnt show image?
You need to add an Icon to the TableModel (not a JLabel). Then you need to tell the table the Icon is stored in the column so the table can choose the appropriate renderer to paint the Icon.
This is done by overriding the getColumnClass(...) method of the TableModel:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableIcon extends JPanel
{
public TableIcon()
{
Icon aboutIcon = new ImageIcon("about16.gif");
Icon addIcon = new ImageIcon("add16.gif");
Icon copyIcon = new ImageIcon("copy16.gif");
String[] columnNames = {"Picture", "Description"};
Object[][] data =
{
{aboutIcon, "About"},
{addIcon, "Add"},
{copyIcon, "Copy"},
};
DefaultTableModel model = new DefaultTableModel(data, columnNames)
{
// Returning the Class of each column will allow different
// renderers to be used based on Class
#Override
public Class getColumnClass(int column)
{
return getValueAt(0, column).getClass();
}
};
JTable table = new JTable( model );
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Table Icon");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TableIcon());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
I need to remove the rows that are selected after a button is pressed.
That's is my code: I have a column that is a checkbox, then a check if it is checked and add the corresponding line to the list.
DefaultTableModel model = (DefaultTableModel) jTableLayouts.getModel();
// gets the number of rows that were selected
Public ArrayList<Integer> selectedLines = new ArrayList<Integer>();
for (int j = 0; j <= jTableLayouts.getModel().getRowCount(); j++) {
if ((Boolean) jTableLayouts.getModel().getValueAt(j,2)){ //checkbox
selectedLines.add(jTableLayouts.getSelectedRow());
}
model.removeRow(selectedLines.get(j));
}
With this code I can remove one by one. Any ideas how I can remove all the lines after a press the button?
EDIT: I only need to remove the rows that are marked as true in the checkbox. Example: the rows 0,1,4,5 are marked as true, after that I will add these lines in a list, and then just remove the lines that are on the list at same time after the button is pressed.
As #MadProgrammer already commented, you can do this from a button by having the ActionListener perform the deletes and add the deleted rows to the list you want.
In this snippet when pressing the button, the checked rows on the left are deleted and added to the table on the right. Check the createDeleteButton method for how this is done.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
#SuppressWarnings("serial")
public class TestTableDeleteRows extends JPanel {
private JTable tblLeft;
private JTable tblRight;
public TestTableDeleteRows() {
initialize();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600,400);
}
private void initialize() {
setLayout(new BorderLayout());
add(createHeaderPane(),BorderLayout.NORTH);
add(createTablePane(),BorderLayout.CENTER);
add(createDeleteButton(),BorderLayout.SOUTH);
}
private JPanel createHeaderPane() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS));
p.add(new JScrollPane(new JLabel("Source",SwingConstants.CENTER)));
p.add(new JScrollPane(new JLabel("Deleted",SwingConstants.CENTER)));
return p;
}
private JPanel createTablePane() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
tblLeft = createTable(stdRows);
tblRight = createTable(new Vector<Vector<Object>>());
p.add(new JScrollPane(tblLeft));
p.add(new JScrollPane(tblRight));
return p;
}
private static final int COL_CHECK=0;
private static final int COL_TEXT=1;
private static final Vector<Vector<Object>> stdRows;
private static final Vector<Object> cols;
static {
stdRows = new Vector<Vector<Object>>();
for(int i=0;i!=100;++i)
stdRows.add(new Vector<Object>(Arrays.asList(new Object[]{Boolean.FALSE,"This is text line number "+(i+1)})));
cols = new Vector<>(Arrays.asList(new Object[]{"Check me","Silly text"}));
}
private static JTable createTable(Vector<Vector<Object>> rows) {
JTable t = new JTable(rows,cols) {
#Override
public Class<?> getColumnClass(int column) {
if(getRowCount()>0)
return getValueAt(0, column).getClass();
return super.getColumnClass(column);
}
};
t.getColumnModel().getColumn(COL_CHECK).setPreferredWidth(50);
t.getColumnModel().getColumn(COL_TEXT).setPreferredWidth(200);
return t;
}
private JButton createDeleteButton() {
JButton b = new JButton("Delete checked rows");
b.addActionListener(new ActionListener() {
#SuppressWarnings("unchecked")
#Override
public void actionPerformed(ActionEvent e) {
Vector<Vector<Object>> removedRows = new Vector<>();
DefaultTableModel modelLeft = (DefaultTableModel) tblLeft.getModel();
for(int r=0;r!=modelLeft.getRowCount();++r)
if((Boolean) modelLeft.getValueAt(r,COL_CHECK)) {
removedRows.add((Vector<Object>) modelLeft.getDataVector().get(r));
modelLeft.removeRow(r--);
}
DefaultTableModel modelRight = (DefaultTableModel) tblRight.getModel();
for(Vector<Object> row : removedRows)
modelRight.addRow(row);
}
});
return b;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Delete checked rows in JTable from button");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new TestTableDeleteRows());
f.pack();
f.setVisible(true);
}
});
}
}
Result:
I get an error when I remove a row a sorted row in a JTable.
The error appears only when the table is sorted, and I know where the error source is:
the method updateRowHeights() in the tableChanged causes an Exception java.lang.ArrayIndexOutOfBoundsException.
I guess that the line int rowHeight = table.getRowHeight(); causes the problem,
but I don't know why.
Here is my code:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class TableExample {
String [] title = new String [] {"Title A", "Title B"};
Object [][] data = new String [][] {{"aaaaaaaaaaaa aaaaaa aaaaaaa", "bbbbbbbb bbbb bbbbbb bbbbbb"},
{"cccccccccc cccccccc ccccccc", "ddddddd ddd dddddddd dddddd"},
{"eeeeeeeeee eeeeeeee eeeeeee", "fffffff ffff ffffff fffffff"}};
private JTable table;
private JFrame frame;
private DefaultTableModel model;
private JScrollPane pane1;
TableExample() {} //constructor
public JPanel createTable() {
JPanel panel = new JPanel();
//creating tables and table models
model = new DefaultTableModel(data, title);
table = new JTable(model);
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
updateRowHeights();
}
});
//enable table sorting
table.setAutoCreateRowSorter(true);
pane1 = new JScrollPane(table);
pane1.setPreferredSize(new Dimension(300,300));
updateRowHeights();
panel.add(pane1);
//delete a row after del keystroke
keyBindings();
return panel;
}
void showTable() {
//create and show frame
JPanel testPanel = createTable();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testPanel);
frame.pack();
frame.setVisible(true);
}//showTable
void updateRowHeights() {
for (int row = 0; row < table.getRowCount(); row++) {
int rowHeight = table.getRowHeight();
Component comp = table.prepareRenderer(table.getCellRenderer(row, 1), row, 1);
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
table.setRowHeight(row, rowHeight);
}
}
void keyBindings() {
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
actionMap.put("delete", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
model.removeRow(row);
}
});
}
public static void main(String[] args) {
TableExample example = new TableExample();
example.showTable();
}//main
}//TableExample
How can I solve this problem?
As noted here, "When using a sorter, always remember to translate cell coordinates." In your delete action, for example,
row = table.convertRowIndexToModel(row);
A similar problem afflicts updateRowHeights(), although I did not pursue this.
Also consider overriding getPreferredScrollableViewportSize(), instead of calling setPreferredSize(); more details here.
As tested:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class TableExample {
String[] title = new String[]{"Title A", "Title B"};
Object[][] data = new String[][]{
{"aaaaaaaaaaaa aaaaaa aaaaaaa", "bbbbbbbb bbbb bbbbbb bbbbbb"},
{"cccccccccc cccccccc ccccccc", "ddddddd ddd dddddddd dddddd"},
{"eeeeeeeeee eeeeeeee eeeeeee", "fffffff ffff ffffff fffffff"}};
private JTable table;
private JFrame frame;
private DefaultTableModel model;
private JScrollPane pane1;
public JPanel createTable() {
JPanel panel = new JPanel();
//creating tables and table models
model = new DefaultTableModel(data, title);
table = new JTable(model);
//enable table sorting
table.setAutoCreateRowSorter(true);
pane1 = new JScrollPane(table);
panel.add(pane1);
//delete a row after del keystroke
keyBindings();
return panel;
}
void showTable() {
//create and show frame
JPanel testPanel = createTable();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testPanel);
frame.pack();
frame.setVisible(true);
}//showTable
void keyBindings() {
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
actionMap.put("delete", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
row = table.convertRowIndexToModel(row);
model.removeRow(row);
}
});
}
public static void main(String[] args) {
TableExample example = new TableExample();
example.showTable();
}//main
}//TableExample