Edit Jtable on double click - java

I need to edit table when user double clicks on row, with new values. I tried with setValuesAt method but it didn't do anything.
This is what I got so far but I don't know how to set new values to Jtable.
public class Table extends JFrame {
private JTable table;
private JScrollPane jsPane;
private DefaultTableModel model;
private JPanel dialogPanel;
private JTextField tf[];
private JLabel lbl[];
private JPanel panel;
Object[] columns = new Object[]{"Name", "Last Name", "ID", "Email"};
Object[][] inData ;
public void prepareAndShowGUI() {
setTitle("Overview");
model = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
model.setColumnIdentifiers(columns);
table = new JTable(model);
for (int i = 1; i <= 10; i++) {
model.addRow(new Object[]{"a", "s", "w", "e"});
}
jsPane = new JScrollPane(table);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int x = e.getX();
int y = e.getY();
int row = table.rowAtPoint(new Point(x, y));
int col = table.columnAtPoint(new Point(x, y));
String array[] = new String[table.getColumnCount()];
for (int i = 0; i < array.length; i++) {
array[i] = (String) table.getValueAt(row, i);
}
populateTextField(array);
JOptionPane.showMessageDialog(null, dialogPanel, "Information", JOptionPane.INFORMATION_MESSAGE);
String[] values = new String[tf.length];
for (int i = 0; i < tf.length; i++) {
values[i] = tf[i].getText();
}
model.setValueAt(values, row, row);
}
}
});
panel = new JPanel(new BorderLayout());
JPanel panel1 = new JPanel();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS));
panel.add(panel1, BorderLayout.NORTH);
panel.add(jsPane, BorderLayout.CENTER);
getContentPane().add(panel);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
prepareDialogPanel();
setVisible(true);
}
private void prepareDialogPanel() {
dialogPanel = new JPanel();
int col = table.getColumnCount();
dialogPanel.setLayout(new GridLayout(col, 1));
tf = new JTextField[col];
lbl = new JLabel[col];
for (int i = 0; i < col; i++) {
lbl[i] = new JLabel(table.getColumnName(i));
tf[i] = new JTextField(10);
dialogPanel.add(lbl[i]);
dialogPanel.add(tf[i]);
}
}
private void populateTextField(String[] s) {
for (int i = 0; i < s.length; i++) {
tf[i].setText(s[i]);
}
}
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
Table td = new Table();
td.prepareAndShowGUI();
}
});
}

For starters, you should make your model editable, so change this line:
model = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
To:
model = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int column) {
return true; //use the row and col to determine which
//cells are editable. If you want all, have this return true.
}
};
This will invoke the JTable's DefaultCellEditor, which will then call on the model's setValueAt method, when the user has made the change on the edit.
All of these components can be replaced with custom components to perform different actions.
Here's the official Oracle documentation on JTables:
https://docs.oracle.com/javase/tutorial/uiswing/components/table.html
If you're trying to get your dialog to work, the problem is in these line:
String[] values = new String[tf.length];
for (int i = 0; i < tf.length; i++) {
values[i] = tf[i].getText();
}
model.setValueAt(values, row, row);
Basically the setValueAt only works on a cell by cell basis. You can't update a whole row like this. Instead try:
for(int i=0;i<tf.length;i++)
{
model.setValueAt(tf[i].getText(), row, i);
}

Related

Is there a way to reference the index of the button above of a clicked button? In Java Swing [duplicate]

How to get position(I mean row and column) of the clicked button with gridlayout?
public void init(final Container pane) {
JPanel controls = new JPanel();
int size = (int) Math.sqrt(puzzle.getSize() + 1);
controls.setLayout(new GridLayout(size, size));
for (int i = 0; i < puzzle.getSize(); i++) {
int k = puzzle.getListItem(i);
if (k == puzzle.getEmptyFlag())
controls.add(new JLabel(""));
else {
JButton jb = new JButton(String.valueOf(k));
jb.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
//get row and column
}
});
controls.add(jb);
}
}
pane.add(controls);
}
Never add a MouseListener on a JButton for that purpose. Use an ActionListener instead.
Why not create an array or ArrayList of JButton and then simply iterate through the list to find the proper one?
i.e.,
private JButton[][] buttonGrid = new JButton[ROWS][COLS];
Elsewhere you will need to fill the grid with viable JButton objects and place those JButtons into your GUI.
Then later in program use a nested for loop iterating through the grid comparing the grid button with the getSource() JButton.
i.e. in the JButton's ActionListener
public void actionPerformed(ActionEvent e) {
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
if buttonGrid[row][col] == e.getSource();
// here you have your row and column
}
}
}
Edit
You ask:
why?
Because it won't work correctly in many situations. ActionListeners have been built to work specifically with JButtons and JMenuItems and have mechanisms that make this function work well l and easily. For example, say you decide to have a JButton that is only enabled once the user has filled two JTextFields, and you use the JButton's setEnabled(boolean enabled) method to do this, disabling the JButton will not stop the MouseListener from working, but it will stop the ActionListener.
Edit 2
For example,
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ButtonGridEg extends JPanel {
private static final int ROWS = 8;
private static final int COLS = ROWS;
private static final int GAP = 5;
private JButton[][] buttonGrid = new JButton[ROWS][COLS];
public ButtonGridEg() {
setLayout(new GridLayout(ROWS, COLS, GAP, GAP));
ActionListener buttonListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
JButton selectedBtn = (JButton) evt.getSource();
for (int row = 0; row < buttonGrid.length; row++) {
for (int col = 0; col < buttonGrid[row].length; col++) {
if (buttonGrid[row][col] == selectedBtn) {
System.out.printf("Selected row and column: %d %d%n", row, col);
}
}
}
}
};
for (int row = 0; row < buttonGrid.length; row++) {
for (int col = 0; col < buttonGrid[row].length; col++) {
String text = String.format("Button [%d, %d]", row, col);
buttonGrid[row][col] = new JButton(text);
buttonGrid[row][col].addActionListener(buttonListener);
add(buttonGrid[row][col]);
}
}
}
private static void createAndShowGui() {
ButtonGridEg mainPanel = new ButtonGridEg();
JFrame frame = new JFrame("ButtonGridEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
In this case, you don't even have to search for the indices, because you know them when the button is created:
for (int i = 0; i < puzzle.getSize(); i++) {
int k = puzzle.getListItem(i);
if (k == puzzle.getEmptyFlag())
controls.add(new JLabel(""));
else {
JButton jb = new JButton(String.valueOf(k));
final int rowIndex = i / size;
final int columnIndex = i % size;
// Using an ActionListener, as Hovercraft Full Of Eels already told you:
jb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("rowIndex "+rowIndex+" columnIndex "+columnIndex);
}
});
controls.add(jb);
}
}

java swing change background to a selected cell (no columns or rows) at time

This code changes the color of all the column, I need to change the single cell color at time. This code creates a table and installs a TableCellRenderer that modify the column color. It has two buttons that perform this action. The code speaks alone.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;
public class Board extends JPanel {
private static final long serialVersionUID = 1L;
int boardHeight = 20;
int boardWidth = 10;
JTable table;
Random random = new Random();
public Board() {
setLayout(new BorderLayout()); // !!
DefaultTableModel model = new
DefaultTableModel(boardHeight, boardWidth) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
};
// !! table = new JTable(this.boardHeight, this.boardWidth);
table = new JTable(model);
for (int row = 0; row < model.getRowCount(); row++) {
for (int col = 0; col < model.getColumnCount(); col++) {
String s = random.nextBoolean() ? "red" : "yellow";
model.setValueAt(s, row, col);
}
}
//table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
BoardTableCellRenderer mcr = new BoardTableCellRenderer();
table.setFocusable(true);
table.setShowGrid(false);
table.setRowMargin(0);
table.setIntercellSpacing(new Dimension(0, 0));
table.setRowSelectionAllowed(false);
table.setFillsViewportHeight(true);
table.setVisible(true);
//this.add(table);
this.setPreferredSize(new Dimension(table.getPreferredSize().width,
(table.getPreferredSize().height + 85)));
javax.swing.JButton b = new javax.swing.JButton("bottone");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
table.getColumnModel().getColumn(table.getSelectedColumn()).setCellRenderer(mcr);
table.revalidate(); table.repaint();
}
});
javax.swing.JButton b1 = new javax.swing.JButton("bottone default");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
table.setDefaultRenderer(String.class, new DefaultTableCellRenderer());
table.revalidate(); table.repaint();
}
});
/*for (int columnIndex = 0; columnIndex < table.getColumnCount(); columnIndex ++) {
table.getColumnModel().getColumn(columnIndex).setCellRenderer(mcr);
}*/
//JScrollPane p1 = new JScrollPane();
//p1.add(table);
add(b, BorderLayout.SOUTH); // e.g. for the button
add(b1, BorderLayout.NORTH); // e.g. for the button
add(table, BorderLayout.CENTER); // e.g. for the button
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Board");
frame.getContentPane().add(new Board());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class BoardTableCellRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, col);
TableModel t = table.getModel();
Object valueAt = table.getModel().getValueAt(row, col);
String s = "";
if (valueAt != null) {
s = valueAt.toString();
}
//if (isSelected) {
// System.out.println("row: "+row+" "+"col: "+col);
if (col == 0 && row == 0) {
c.setForeground(Color.YELLOW);
c.setBackground(Color.gray);
}
//}
/* if (s.equalsIgnoreCase("yellow")) {
c.setForeground(Color.YELLOW);
c.setBackground(Color.gray);
} else {
c.setForeground(Color.black);
c.setBackground(Color.WHITE);
}
*/
return c;
}
}
This code changes the color of all the column,
The same renderer is used by all cells in the column.
So you need code something like:
if (!isSelected)
{
if (your special condition)
{
c.setBackground(...);
}
else // reset background to the default
{
c.setBackground(table.getBackground();
}
}

Java: Automatically Update a Checkbox in JTable when Another Checkbox is Clicked

I want every checkbox in the JTable in the EventYearMatchingUnitPanel class to be selected automatically when a checkbox in the JTable in EventYearMatchingWindow is clicked.
clicking the "unit 9" checkbox in the first picture (https://ibb.co/fsqtrQ) should automatically select all 5 checkboxes in the second picture (https://ibb.co/f8ja5k)
I used the tableChanged() method in TabelModelListener to detect if a checkbox is clicked. When I click the checkbox, it changes the value of the other checkboxes (from Boolean.FALSE to Boolean.TRUE), but the checkboxes don't update (don't physically show the checkmarks).
//for the first JTable
public void tableChanged(TableModelEvent e){
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel)e.getSource();
String columnName = model.getColumnName(column);
Object thatValue = model.getValueAt(row, column);
data[row][column] = thatValue;
for(int i = 0; i < unitPanels[row].getNumRows(); i++){
unitPanels[row].setToSelectedState(i);
}
}
//for the second JTable
public void setToSelectedState(int row){
data[row][0] = Boolean.TRUE;
model.fireTableCellUpdated(row, 0);
}
Here's a bigger picture of the code:
public class EventYearMatchingWindow extends JFrame implements
TableModelListener
{
private boolean columnHeaderClicked;
private ArrayList<Category> categories;
private JPanel mainPanel, listPanel, buttonPanel;
private ArrayList<Item> selectedItems;
private EventYearMatchingItemChoosing[] unitPanels;
Object data[][];
public EventYearMatchingWindow(ArrayList<Category> c){
...
String[] columnNames = {"Include?", ""};
data = new Object[6][2];
for(int i = 0; i < 6; i++){
data[i][0] = Boolean.FALSE;
data[i][1] = "Unit " + (i+8);
}
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int columnIndex) {
if (columnIndex == 0){
return Boolean.class;
}
return super.getColumnClass(columnIndex);
}
};
JTable table = new JTable(model);
table.getModel().addTableModelListener(this);
table.addMouseListener(new java.awt.event.MouseAdapter() {
....
#Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
int row = table.rowAtPoint(evt.getPoint());
int col = table.columnAtPoint(evt.getPoint());
if (row == -1 && col >= 0){
columnHeaderClicked = true;
}
if (row >= 0 && col == 1 && !columnHeaderClicked) {
mainPanel.removeAll();
System.out.println(unitPanels[row].getData()[0][0]);
unitPanels[row].revalidate();
unitPanels[row].repaint();
mainPanel.add(unitPanels[row]);
JPanel nButtonPanel = new JPanel();
Button back = new Button("Back");
nButtonPanel.add(back);
back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
mainPanel.removeAll();
mainPanel.add(listPanel);
mainPanel.add(buttonPanel);
mainPanel.revalidate();
repaint();
}
});
mainPanel.add(nButtonPanel);
mainPanel.revalidate();
repaint();
}
}
});
}
public void tableChanged(TableModelEvent e){
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel)e.getSource();
String columnName = model.getColumnName(column);
Object thatValue = model.getValueAt(row, column);
data[row][column] = thatValue;
for(int i = 0; i < unitPanels[row].getNumRows(); i++){
unitPanels[row].setToSelectedState(i);
}
}
}
And:
public class EventYearMatchingItemChoosing extends JPanel implements TableModelListener
{
Category category;
private boolean columnHeaderClicked;
private int size;
private ArrayList<Item> items;
private Object[][] data;
DefaultTableModel model;
public EventYearMatchingItemChoosing(String s, ArrayList<Category> c){
...
String[] columnNames = {"Include?", "Event", "Year"};
data = new Object[size][3]
for(int i = 0; i < category.getItems().size(); i++){
if(!category.getItems().get(i).getEvent().equals("") && !category.getItems().get(i).getYear().equals("")){
data[i][0] = Boolean.FALSE;
data[i][1] = category.getItems().get(i).getEvent();
data[i][2] = category.getItems().get(i).getYear();
}
}
model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int columnIndex) {
if (columnIndex == 0){
return Boolean.class;
}
return super.getColumnClass(columnIndex);
}
};
JTable table = new JTable(model);
table.getModel().addTableModelListener(this);
...
}
...
public void tableChanged(TableModelEvent e){
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel)e.getSource();
String columnName = model.getColumnName(column);
Object thatValue = model.getValueAt(row, column);
data[row][column] = thatValue;
}
public void setToSelectedState(int row){
data[row][0] = Boolean.TRUE;
model.fireTableCellUpdated(row, 0);
}
}
but the checkboxes don't update (don't physically show the checkmarks).
data[row][0] = Boolean.TRUE;
Don't ever access the data Array. The data Array is used to create the DefaultTableModel and then the data is copied from the Array to the data structure used by the DefaultTableModel (which happens to be a Vector of Vectors).
The end result is that the data in the TableModel is never changed.
The code should be:
model.setValueAt(Boolean.TRUE, row, 0);

Access outer class member from inner class

I am using Inner class for the first. I am trying to access a variable table which is declared in outer class, in the inner class MyTableModel. But netbeans is showing the error-Cannot find symbol
This is the complete code.
Import Statements
public class TableDemo extends JPanel {
private boolean DEBUG = true;
public TableDemo() {
super(new GridLayout(1,0));
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"First Name","Last Name","Sport","# of Years","Dada","Vegiterian"};
private Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", new Integer(5), new Boolean(false),new Boolean(false)},
};
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
public void setValueAt(Object value, int row, int col) {
}
private void printDebugData() {
TableColumn column = null;
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
if (i == 2) {
column.setPreferredWidth(100); //third column is bigger
} else {
column.setPreferredWidth(50);
}
}
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableDemo newContentPane = new TableDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
and this is the code in which I am getting the error -
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
if (i == 2) {
column.setPreferredWidth(100); //third column is bigger
} else {
column.setPreferredWidth(50);
}
int the line - column = table.getColumnModel().getColumn(i); I am getting the error like - variable table is not found
Please help.
You define the variable in the constructor and not as an instance member. After the constructor code ends, the variable is out of scope. You need to do it like this:
public class TableDemo extends JPanel {
private boolean DEBUG = true;
private JTable table;
public TableDemo() {
super(new GridLayout(1,0));
table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
// Rest of code
You are declaring variable only locally in the constructor. After the constructor is gone (out of scope), the variable is gone. To do it properly, you should define it in a field:
public class TableDemo extends JPanel {
private boolean DEBUG = true;
private JTable table; //define here
public TableDemo() {
super(new GridLayout(1,0));
table = new JTable(new MyTableModel()); //remove Type here
You need an instance variable to access it from an inner class. Your variable has only local scope to the constructor therefore nothing outside the constructor could find it.
Change your code to:
public class TableDemo extends JPanel {
private JTable table;
public TableDemo() {
table = new JTable(new MyTableModel());
//more code
}
// more code
}

How to adjust JTable columns to fit the longest content in column cells

I'm using answer https://stackoverflow.com/a/5820366 and http://tips4java.wordpress.com/2008/11/10/table-column-adjuster/ and it works, but frequently columns' sizes are too wide or too narrow.
No matter filling my table with HTML or text.
Using standard TableModel from oracle documentation.
Resize mode = JTable.AUTO_RESIZE_OFF
Container of my tabel is jGoodies:
FormLayout currentEventLayout = new FormLayout(
"fill:p",
"pref, pref");
PanelBuilder currentEventBuilder = new PanelBuilder(currentEventLayout);
currentEventBuilder.add(mainQuotesTable.getTableHeader(), constraints.xy(1, 1));
currentEventBuilder.add(mainQuotesTable, constraints.xy(1, 2));
HTML example:
"<html><pre><font size=+1 face='Arial'>" + firstValue + "\n" + secondValue + "</font></pre></html>"
simple row:
firstValue + " - " + secondValue
Here is the example:
public class TableAdjustExample {
private static JTable mainTable;
private static Random random = new Random();
private static List<Data> data;
private static class Data {
String name;
String surname;
private Data(String name, String surname) {
this.name = name;
this.surname = surname;
}
}
public static void main(String[] args) {
data = stubProvider();
final JFrame frame = new JFrame("table adjust example");
frame.add(createUI());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(350, 400);
frame.setVisible(true);
update();
java.util.Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
update();
}
}, 3000, 3000);
}
private static JPanel createUI() {
JPanel jPanel = new JPanel();
mainTable = new JTable(2, 3);
mainTable.setModel(new AbstractTableModel() {
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Data dataItem = data.get(rowIndex);
if (columnIndex == 0) {
return dataItem.name;
}
if (columnIndex == 1) {
return dataItem.surname;
}
throw new IllegalStateException();
}
});
mainTable.setGridColor(Color.black);
mainTable.setShowHorizontalLines(false);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
final TableCellRenderer defaultRenderer = mainTable.getTableHeader().getDefaultRenderer();
mainTable.getTableHeader().setDefaultRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable jTable, Object o, boolean b, boolean b1, int row, int column) {
JLabel parent = (JLabel) defaultRenderer.getTableCellRendererComponent(jTable, o, b, b1, row, column);
if (column == 0) {
parent.setText("name");
} else {
parent.setText("surname");
}
return parent;
}
});
jPanel.add(mainTable.getTableHeader());
jPanel.add(mainTable);
return jPanel;
}
private static void update() {
System.out.println("updating");
data = stubProvider();
adjustJTableRowSizes(mainTable);
for (int i = 0; i < mainTable.getColumnCount(); i++) {
adjustColumnSizes(mainTable, i, 2);
}
}
private static void adjustJTableRowSizes(JTable jTable) {
for (int row = 0; row < jTable.getRowCount(); row++) {
int maxHeight = 0;
for (int column = 0; column < jTable.getColumnCount(); column++) {
TableCellRenderer cellRenderer = jTable.getCellRenderer(row, column);
Object valueAt = jTable.getValueAt(row, column);
Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(jTable, valueAt, false, false, row, column);
int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
maxHeight = Math.max(heightPreferable, maxHeight);
}
jTable.setRowHeight(row, maxHeight);
}
}
public static void adjustColumnSizes(JTable table, int column, int margin) {
DefaultTableColumnModel colModel = (DefaultTableColumnModel) table.getColumnModel();
TableColumn col = colModel.getColumn(column);
int width;
TableCellRenderer renderer = col.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
JLabel comp = (JLabel) renderer.getTableCellRendererComponent(
table, col.getHeaderValue(), false, false, 0, 0);
width = comp.getPreferredSize().width;
for (int r = 0; r < table.getRowCount(); r++) {
renderer = table.getCellRenderer(r, column);
comp = (JLabel) renderer.getTableCellRendererComponent(
table, table.getValueAt(r, column), false, false, r, column);
int currentWidth = comp.getPreferredSize().width;
width = Math.max(width, currentWidth);
}
width += 2 * margin;
col.setPreferredWidth(width);
}
private static List<Data> stubProvider() {
List<Data> data = new ArrayList<Data>();
for (int i = 0; i < 4; i++) {
data.add(new Data(
"<html>" +
"<div style='font-size: 15px'>Jason</div>" +
"<div style='font-size: 15px'>" + random.nextInt() + "</div>" +
"</html>",
"Statham " + random.nextInt()));
}
return data;
}
}
I have such problem with row height adjustment. Using of <pre>\n</pre> instead of <br> fixed row adjustment.
Seems to be working okay for me...
public class TestTable01 extends JPanel {
private JTable mainTable;
public TestTable01() {
super(new GridLayout(1, 0));
String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", new Integer(5), new Boolean(false)},
{"John", "Doe",
"Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black",
"Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White",
"Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown",
"Pool", new Integer(10), new Boolean(false)}
};
mainTable = new JTable(data, columnNames);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
mainTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
mainTable.setFillsViewportHeight(true);
update();
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(mainTable);
//Add the scroll pane to this panel.
add(scrollPane);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
TestTable01 newContentPane = new TestTable01();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
private void update() {
System.out.println("updating");
adjustJTableRowSizes(mainTable);
for (int i = 0; i < mainTable.getColumnCount(); i++) {
adjustColumnSizes(mainTable, i, 2);
}
}
private void adjustJTableRowSizes(JTable jTable) {
for (int row = 0; row < jTable.getRowCount(); row++) {
int maxHeight = 0;
for (int column = 0; column < jTable.getColumnCount(); column++) {
TableCellRenderer cellRenderer = jTable.getCellRenderer(row, column);
Object valueAt = jTable.getValueAt(row, column);
Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(jTable, valueAt, false, false, row, column);
int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
maxHeight = Math.max(heightPreferable, maxHeight);
}
jTable.setRowHeight(row, maxHeight);
}
}
public void adjustColumnSizes(JTable table, int column, int margin) {
DefaultTableColumnModel colModel = (DefaultTableColumnModel) table.getColumnModel();
TableColumn col = colModel.getColumn(column);
int width;
TableCellRenderer renderer = col.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(table, col.getHeaderValue(), false, false, 0, 0);
width = comp.getPreferredSize().width;
for (int r = 0; r < table.getRowCount(); r++) {
renderer = table.getCellRenderer(r, column);
comp = renderer.getTableCellRendererComponent(table, table.getValueAt(r, column), false, false, r, column);
int currentWidth = comp.getPreferredSize().width;
width = Math.max(width, currentWidth);
}
width += 2 * margin;
col.setPreferredWidth(width);
col.setWidth(width);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
UPDATED
There are a number of issues with your example.
Tables really should be added to a JScrollPane, this will take care of adding the header...
The default layout manager for a JPanel is FlowLayout, in this case, it's probably not what you want, you probably want to use a BorderLayout
Swing is not thread safe. The user of java.util.Timer will violate this policy, this could cause the model and view to fall out sync. Use a javax.swing.Timer instead.
Rendering two <div> next to each will cause the html layout engine to place a weak break between the elements. That is, if the engine decides there's not enough available space to render the two elements together, it will split them. Better to use a single <div> with two <span> tags instead...
I would have a read of
Concurrency in Swing
How to Use Tables
public class TestColumnWidths {
private static JTable mainTable;
private static Random random = new Random();
private static List<Data> data;
private static class Data {
String name;
String surname;
private Data(String name, String surname) {
this.name = name;
this.surname = surname;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
data = stubProvider();
final JFrame frame = new JFrame("table adjust example");
frame.add(createUI());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
update();
// java.util.Timer timer = new java.util.Timer();
// timer.schedule(new TimerTask() {
// #Override
// public void run() {
// update();
// }
// }, 3000, 3000);
javax.swing.Timer timer = new javax.swing.Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
private static JPanel createUI() {
JPanel jPanel = new JPanel();
mainTable = new JTable(2, 3);
mainTable.setModel(new AbstractTableModel() {
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Data dataItem = data.get(rowIndex);
if (columnIndex == 0) {
return dataItem.name;
}
if (columnIndex == 1) {
return dataItem.surname;
}
throw new IllegalStateException();
}
});
mainTable.setGridColor(Color.black);
mainTable.setShowHorizontalLines(false);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
final TableCellRenderer defaultRenderer = mainTable.getTableHeader().getDefaultRenderer();
mainTable.getTableHeader().setDefaultRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable jTable, Object o, boolean b, boolean b1, int row, int column) {
JLabel parent = (JLabel) defaultRenderer.getTableCellRendererComponent(jTable, o, b, b1, row, column);
if (column == 0) {
parent.setText("name");
} else {
parent.setText("surname");
}
return parent;
}
});
// jPanel.add(mainTable.getTableHeader());
// jPanel.add(mainTable);
jPanel.setLayout(new BorderLayout());
jPanel.add(new JScrollPane(mainTable));
return jPanel;
}
private static void update() {
System.out.println("updating");
data = stubProvider();
adjustJTableRowSizes(mainTable);
for (int i = 0; i < mainTable.getColumnCount(); i++) {
adjustColumnSizes(mainTable, i, 2);
}
}
private static void adjustJTableRowSizes(JTable jTable) {
for (int row = 0; row < jTable.getRowCount(); row++) {
int maxHeight = 0;
for (int column = 0; column < jTable.getColumnCount(); column++) {
TableCellRenderer cellRenderer = jTable.getCellRenderer(row, column);
Object valueAt = jTable.getValueAt(row, column);
Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(jTable, valueAt, false, false, row, column);
int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
maxHeight = Math.max(heightPreferable, maxHeight);
}
jTable.setRowHeight(row, maxHeight);
}
}
public static void adjustColumnSizes(JTable table, int column, int margin) {
DefaultTableColumnModel colModel = (DefaultTableColumnModel) table.getColumnModel();
TableColumn col = colModel.getColumn(column);
int width;
TableCellRenderer renderer = col.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(
table, col.getHeaderValue(), false, false, 0, 0);
width = comp.getPreferredSize().width;
for (int r = 0; r < table.getRowCount(); r++) {
renderer = table.getCellRenderer(r, column);
comp = renderer.getTableCellRendererComponent(
table, table.getValueAt(r, column), false, false, r, column);
int currentWidth = comp.getPreferredSize().width;
width = Math.max(width, currentWidth);
}
width += 2 * margin;
col.setPreferredWidth(width);
}
private static List<Data> stubProvider() {
List<Data> data = new ArrayList<Data>();
for (int i = 0; i < 4; i++) {
data.add(new Data(
"<html>"
+ "<div>"
+ "<span style='font-size: 15px'>Jason</span>"
+ "<span style='font-size: 15px'>" + random.nextInt() + "</span>"
+ "</div>"
+ "</html>",
"Statham " + random.nextInt()));
}
return data;
}
}
Set reasonable MinimumWidth for the columns which are too narrow. Then calculate width according to the contents of the columns and set them.

Categories