JTable how prepareEditor works
I think the prepareRenderer(...)
code should be:
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if ((column == 2 || column == 3) && (Boolean)getValueAt(row, 0)) {
return c;
}
// if (column == 0 || column == 1 || (Boolean) getValueAt(row, 0)) {
if (column == 0 || column == 1) {
return c;
}
return Box.createRigidArea(c.getPreferredSize());
}
Then you should get rid of the prepareEditor(...)
code. Instead you should have more logic in the isCellEditable(...)
method. Something like:
public boolean isCellEditable(int row, int column) {
if (column == 0) return true;
if (column == 1 || column == 4 || column == 5) return false;
return (Boolean)getValueAt(row, 0);
}
jFileChooser as cell editor in a table
The tutorial approach is correct. See this example that use an undecorated JButton
to evoke the actual editor. Instead of PopupDialog
, you'll use JFileChooser
.
Addendum: To apply the editor to any cell(s) individually, override prepareEditor()
for the desired row and column, as discussed here.
Set Condition for JTable, Java
You should handle this within your domain (e.g. add a constraint wherever you maintain your data loaded into the tableModel) and limit the amount of senior managers there. This is business logic, don't implement it in your GUI.
Select all data when start editing JTable Cell
You can create a custom TableCellEditor for your table. This class will have an instance variable of a TextField
, lets call it textField
. Then the getTableCellEditorComponent
method could look like this:
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column ) {
textField.setText(value.toString());
textField.selectAll();
return textField;
}
JTable - multi-type column
You should implement your custom TableCellRenderer and TableCellEditor.
Then retrieve the TableColumn you need to customize and set your class where you implemented those interfaces.
TableColumn column = table.getColumnModel().getColumn(vColIndex);
column.setCellRenderer(new YourCustomCellRenderer());
column.setCellEditor(new YourCustomCellEditor());
JTable valuechanged then change cell color
Tables use a TableCellRenderer
to paint values on the screen. The editors and renderers don't actually have anything to do with each other (from a painting point of view).
So once the editor has been dismissed (accepted or cancelled), the cell is repainted using the assigned TableCellRenderer
You need to supply, in your table model, some way to determine which rows have been updated and change the state of the renderer to match.
FYI- The DefaultTableCellRenderer
uses a JLabel
as it's base renderer, so it is transparent by default; you will need to make it opaque to make it render properly.
Check out Using custom renderers for more details
Update with example
This is nothing more then a proof of concept. It will not meet your absolute requirements and you should take a serious look at the tutorial linked above.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
public class TableEdit {
public static void main(String[] args) {
new TableEdit();
}
public TableEdit() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTable table = new JTable(new MyTableModel());
table.setSurrendersFocusOnKeystroke(true);
TableColumnModel model = table.getColumnModel();
model.getColumn(1).setCellRenderer(new MyTableCellRenderer());
add(new JScrollPane(table));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class MyData {
private String key;
private String value;
private boolean changed;
public MyData(String key, String value) {
this.key = key;
this.value = value;
this.changed = false;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
public void setValue(String newValue) {
if (value == null ? newValue != null : !value.equals(newValue)) {
value = newValue;
changed = true;
}
}
public boolean hasChanged() {
return changed;
}
}
public class MyTableModel extends AbstractTableModel {
private List<MyData> data;
public MyTableModel() {
data = new ArrayList<>(25);
for (int index = 0; index < 5; index++) {
data.add(new MyData("A" + (index + 1), "B" + (index + 1)));
}
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
MyData myData = data.get(rowIndex);
Object value = null;
switch (columnIndex) {
case 0:
value = myData.getKey();
break;
case 1:
value = myData.getValue();
break;
}
return value;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 1;
}
public boolean hasChanged(int rowIndex) {
MyData myData = data.get(rowIndex);
return myData.hasChanged();
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
MyData myData = data.get(rowIndex);
myData.setValue(aValue == null ? null : aValue.toString());
}
}
public class MyTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setOpaque(isSelected);
TableModel model = table.getModel();
if (model instanceof MyTableModel) {
MyTableModel myModel = (MyTableModel) model;
if (myModel.hasChanged(row)) {
if (!isSelected) {
setBackground(Color.RED);
setOpaque(true);
}
}
}
return this;
}
}
}
Trouble detecting mouse click in JTable
@camickr - thank you for the answer. I overrode the prepareEditor method as suggested which updates the ListModel in the combo box as required.
JTable typeTable = new JTable() {
@Override
public Component prepareEditor(TableCellEditor editor, int row, int column) {
if (column == SUBTYPE_COLUMN) {
// User has entered a subtype cell
// Get value of the adjacent type cell
updateCBOSubtypeDataModel(myTableModel.getValueAt(row, TYPE_COLUMN);
}
return super.prepareEditor(editor, row, column);
}
};
and
private void updateCBOSubtypeDataModel(TypeObject newType) {
myComboBoxListModel.removeAllElements();
myComboBoxListModel.addAll(getListOfSubtypesForThisType(newType));
}
Working nicely. Thanks.
How to change background color of an edited cell in JTable?
First, get the table's default selection background color:
Color color = UIManager.getColor("Table.selectionBackground");
Second, override prepareEditor()
, as shown in this example, and set the background color of the editor component to match:
@Override
public Component prepareEditor(TableCellEditor editor, int row, int col) {
Component c = super.prepareEditor(editor, row, col);
c.setBackground(color);
return c;
}
Addendum: While technically correct, note that the editor component's color is typically managed by the corresponding UI delegate while active. An unfortunate choice may result in poor contrast and impaired usability. Thorough testing on target Look & Feels is warranted.
strange behavior of customized JPanel inside a JTable
Somehow I managed to solve it. Thank you @Oliver Watkins for your kind help.
As summary to my fix, I addedrendererJPanel = (CustomJPanel) value;
for both getTableCellRendererComponent() and getTableCellEditorComponent()
Comple code :
CustomJTableTest.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class CustomJTableTest extends JPanel
{
TableModel customRendererEditorTableModel = new TableModel();
JTable table;
public CustomJTableTest()
{
setLayout(new BorderLayout());
table = new JTable(customRendererEditorTableModel);
table.setPreferredScrollableViewportSize(new Dimension(500, 600));
table.setRowSelectionAllowed(false);
table.setRowHeight(300);
table.getColumn("Custom JPanel").setCellRenderer(new CustomJPanelRenderer());
table.getColumn("Custom JPanel").setCellEditor(new CustomJPanelEditor());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
JButton showControl = new JButton("Show Controls");
showControl.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
// row 2
TableCellEditor tableCellEditor = table.getColumnModel().getColumn(1).getCellEditor();
java.awt.Component component = table.prepareEditor(tableCellEditor, 1, 1);
if (component instanceof CustomJPanel)
{
CustomJPanel customJPanel = (CustomJPanel) component;
customJPanel.setControlsVisible(true);
}
// row 1
java.awt.Component component2 = table.prepareEditor(tableCellEditor, 0, 1);
if (component2 instanceof CustomJPanel)
{
CustomJPanel customJPanel = (CustomJPanel) component2;
customJPanel.setControlsVisible(true);
}
customRendererEditorTableModel.fireTableDataChanged();
}
});
add(new JScrollPane(showControl), BorderLayout.SOUTH);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Custom JPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new CustomJTableTest();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
CustomJPanel.java
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
public class CustomJPanel extends JPanel
{
JPanel colorPanel = new JPanel(new BorderLayout());
JButton jButton = new JButton("Change Color");
JSlider jSlider = new JSlider(JSlider.VERTICAL);
public CustomJPanel()
{
jButton.setOpaque(true);
jButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(4);
switch (randomInt)
{
case (0):
colorPanel.setBackground(Color.BLUE);
break;
case (1):
colorPanel.setBackground(Color.BLACK);
break;
case (2):
colorPanel.setBackground(Color.CYAN);
break;
default:
colorPanel.setBackground(Color.GREEN);
break;
}
}
});
jSlider.setOpaque(true);
setLayout(new BorderLayout());
add(colorPanel, BorderLayout.CENTER);
add(jButton, BorderLayout.SOUTH);
add(jSlider, BorderLayout.EAST);
jSlider.setVisible(false);
jButton.setVisible(false);
}
public void setControlsVisible(boolean visible)
{
jSlider.setVisible(visible);
jButton.setVisible(visible);
}
}
CustomerJPanelRenderer
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class CustomJPanelRenderer implements TableCellRenderer
{
CustomJPanel rendererJPanel;
public CustomJPanelRenderer()
{
rendererJPanel = new CustomJPanel();
}
@Override
public java.awt.Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
rendererJPanel = (CustomJPanel) value;
return rendererJPanel;
}
}
CustomJPanelEditor.java
import javax.swing.AbstractCellEditor;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class CustomJPanelEditor extends AbstractCellEditor implements TableCellEditor
{
CustomJPanel customJPanel;
public CustomJPanelEditor()
{
customJPanel = new CustomJPanel();
}
@Override
public java.awt.Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
customJPanel = (CustomJPanel) value;
return customJPanel;
}
@Override
public Object getCellEditorValue()
{
return customJPanel;
}
}
TableModel.java
import javax.swing.table.AbstractTableModel;
public class TableModel extends AbstractTableModel
{
private String[] columnNames =
{
"First Column",
"Custom JPanel",
};
private Object[][] data =
{
{"Foo", new CustomJPanel()},
{"Bar", new CustomJPanel()}
};
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)
{
return col >= 1;
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
Related Topics
Gson and Deserializing an Array of Objects with Arrays in It
List All Files in the Folder and Also Sub Folders
Possible to Use Two Java Classes with Same Name and Same Package
Class Object of Generic Class (Java)
Java - How to Create New Entry (Key, Value)
Spring 4 - Addresourcehandlers Not Resolving the Static Resources
Right Way to Write JSON Deserializer in Spring or Extend It
How to Find Out If "Debug Mode" Is Enabled
Character Encoding Detection Algorithm
Jframe.Dispose() VS System.Exit()
Difference Between Wait and Blocked Thread States
Converting to Upper and Lower Case in Java