i'm trying to render some icons in a JTable header without success. I've already tried something like this: http://www.java2s.com/Tutorial/Java/0240__Swing/CustomizingColumnHeaderswithIcons.htm
but it doesn't show any icon in the header. How can I reach this goal?
Your link is good code , but in fact when you load a picture using absolute path or relative path , this code is not portable .So it is better to load picture from a class. Levels :
1) Create a empty class with this name : ImageResources
2) Please copy your picture
3) Please find ImageResources class in package explorer (in eclipse) and do right click on it (ImageResources) and press "Paste" menuItem.
4) Finally you need a small change in your code like this
ImageIcon blueIcon = new ImageIcon(ImageResources.class.getResource(yourPictureName));
It is working :)
Below method worked for me.
MyTable.getColumn("ColumnName").setHeaderRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
return new JLabel(new ImageIcon(getClass().getResource("/project/img/ImgName.png")));
}
});
The question is a bit older, but I was only now faced with the same question.
Another approach is to override the TableModel's getColumnName function. HTML formatted text is supported.
Here is the sample code:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class TableColumnHeaderIcon {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TableModel tableModel = new AbstractTableModel() {
#Override
public String getColumnName(int columnIndex) {
// Build the html formatted text
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<img src=\"https://via.placeholder.com/16/007AAE/\">");
sb.append(" Column Title");
sb.append("</html>");
return sb.toString();
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public int getRowCount() {
return 0; // No data required
}
#Override
public Object getValueAt(int i, int i1) {
return null; // No data required
}
};
// Setup UI
JScrollPane scrollPaneTable = new JScrollPane();
JTable table = new JTable(tableModel);
scrollPaneTable.setViewportView(table);
JFrame mdi = new JFrame("Test JTable Column Header with Icon");
mdi.setSize(600, 400);
mdi.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mdi.add(scrollPaneTable);
mdi.setVisible(true);
});
}
}
Related
I have a Swing UI element that uses nested JTables. That is, the TableCellRenderer of the outer table returns JTable objects as the Component to render for each cells. This code works great under Java 8. Using the exact same code under Java 9 or Java 10 causes the inner table to not be repainted properly when scrolling the table. The table IS repainted properly when the window is resized.
Edit:
I did some more digging and traced the problem to lines 1862:1877 in BasicTableUI.java - these lines were added in Java 9. If I make my own TableUI without these lines, the problem disappears. From debugging, it appears that the issue is that in my case rMin and rMax are equal and setting rMax = rMax - 1 makes rMax < rMin which is obviously is bad. The added code seems to be there to deal with issues printing a table. Not sure why nested tables makes this break.
See the SSCE below:
package testing.test_painting;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class InnerTable extends JTable {
public InnerTable(TableModel dm) {
super(dm);
}
}
class InnerTableModel extends AbstractTableModel {
#Override
public int getRowCount() {
return 500;
}
#Override
public int getColumnCount() {
return 10;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return rowIndex + "," + columnIndex;
}
}
class OuterTableModel extends AbstractTableModel {
private final List<JTable> termTables;
public OuterTableModel() {
this.termTables = Arrays.asList(new InnerTable(new InnerTableModel()));
}
#Override
public int getRowCount() {
return 1;
}
#Override
public int getColumnCount() {
return termTables.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return termTables.get(columnIndex);
}
public JTable getTermTable(int modelColumn) {
return termTables.get(modelColumn);
}
}
class OuterTable extends JTable {
private final List<TableRenderer> renderers;
private class TableRenderer implements TableCellRenderer {
private final OuterTableModel tableModel;
public TableRenderer(OuterTableModel tableModel) {
this.tableModel = tableModel;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
int modelColumn = convertColumnIndexToModel(column);
JTable termTable = tableModel.getTermTable(modelColumn);
termTable.setVisible(true);
return termTable;
}
}
private final OuterTableModel tableModel;
public OuterTable(OuterTableModel tableModel) {
super(tableModel);
renderers = new ArrayList<>(tableModel.getColumnCount());
for (int i = 0; i < tableModel.getColumnCount(); i++) {
renderers.add(new TableRenderer(tableModel));
}
this.tableModel = tableModel;
setCellDimensions();
}
#Override
public void setTableHeader(JTableHeader tableHeader) {
tableHeader.setUI(new BasicTableHeaderUI());
super.setTableHeader(tableHeader);
}
private void setCellDimensions() {
Dimension preferredSize = tableModel.getTermTable(0).getPreferredSize();
if (getRowHeight() != preferredSize.height) {
setRowHeight(preferredSize.height);
}
TableColumnModel columnModel = getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumn column = columnModel.getColumn(i);
column.setMinWidth(preferredSize.width);
column.setMaxWidth(preferredSize.width);
column.setPreferredWidth(preferredSize.width);
column.setWidth(preferredSize.width);
}
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
}
#Override
public TableCellRenderer getCellRenderer(int row, int column) {
return renderers.get(column);
}
}
public class TestNestedTable {
public static void main(String[] args) {
OuterTableModel mainTableModel = new OuterTableModel();
OuterTable mainTable = new OuterTable(mainTableModel);
JFrame jFrame = new JFrame();
JScrollPane scrollPane = new JScrollPane(mainTable);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
jFrame.getContentPane().add(scrollPane);
jFrame.pack();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
}
}
make my own TableUI without these lines, the problem disappears.
Or simpler, you might be able to use JViewport#SIMPLE_SCROLL_MODE:
JScrollPane scrollPane = new JScrollPane(mainTable);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
scrollPane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
I know its and old question, but I had the same issue and maybe someone else with the same problem finds this helpful.
This is an JDK bug reported several times (so a lot of duplicates) but most information can be found in the following ticket:
https://bugs.openjdk.java.net/browse/JDK-8202702
There has been added these lines to the BasicTableUI:
// Do not decrement rMax if rMax becomes
// less than or equal to rMin
// else cells will not be painted
if (rMax - rMin > 1) {
rMax = rMax - 1;
}
(s. http://hg.openjdk.java.net/jdk/client/rev/3ba3d39b91c7
or
https://github.com/openjdk/jdk/commit/bb9fed1008dee377725dc669401c389da685f618#diff-ae77528c5d554a9870371e7075801adc4ecd8f992ff484804f164b692b388858)
It is fixed for JDK 12 onward. Unfortunaltey, it is not backported to JDK 11, so if you are forced to use this LTS version one can either do it like #MattWallace and use own TableUI or you can overwrite your Table extending JTable with
#Override
public int getSelectedRow()
{
final int i = super.getSelectedRow();
return i == -1 ? -2 : i;
}
This might bring the problems back mentioned in BasicTableUI comments:
// We did rMax-1 to paint the same number of rows that are drawn on console
// otherwise 1 extra row is printed per page than that are displayed
// when there is no scrollPane and we do printing of table
// but not when rmax is already pointing to index of last row
// and if there is any selected rows
But if you can live with that, this can be also a workaround. Other workarounds like wrapping the Table in a JViewPort or a JScrollPane I cannot recommend as I got size issues with tables which can have changing row heights due to long texts.
I've had a quick Google around, and I can't seem to find a good solution to this, mostly because I'm not sure how to describe it.
Essentially, I need to display an arbitrary amount of hex characters in a JTextArea, and I'd like to have them spaced evenly, and have the positions of the characters shown at the top and left of the characters.
This is an example of what I'd like to achieve, this is the hex viewer WinHex.
I've been playing around with converting a byte array to a String, and then text-wrapping it, but I've had some odd results. Any advice on how to achieve something similar to this would be appreciated.
Another option I've considered is using a JTable, but I'm wondering if that's over complicating the matter slightly. Maybe.
Thanks
I've considered is using a JTable, but I'm wondering if that's over complicating the matter slightly
A decade ago, when I was trying to understand JTable I created myself a simple hex editor to try to understand table models, renderers and editors.
Check out Hex Editor for my result. Just unzip the file and compile all the java files and then execute the Hex class.
I haven't looked at the code in 10 years so I don't know if I followed all best coding practices, but have fun anyway.
This should get you started, using a very simple implementation of AbstractTableModel. This only took me 15 minutes to write (in response to "overcomplicating the issue").
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class HexText extends JFrame {
public static void main(String... args) {
final HexText window = new HexText();
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});
}
private static class HexTableModel extends AbstractTableModel {
List<Integer> data = new ArrayList<>();
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return 9;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return Integer.toHexString(rowIndex << 5);
} else {
int row = data.get(rowIndex);
int theByte = 0xFF & (row >> (columnIndex * 2));
String output = Integer.toHexString(theByte);
if (output.length() == 1)
output = "0" + output;
return output;
}
}
public void addRow(int rowElement) {
data.add(rowElement);
fireTableRowsInserted(data.size() - 1, data.size() - 1);
}
}
public HexText() {
JPanel contentPane = new JPanel(new BorderLayout());
HexTableModel theModel = new HexTableModel();
JTable theTable = new JTable(theModel);
Random r = new Random();
for (int i = 0; i < 20; i++) {
theModel.addRow(r.nextInt());
}
contentPane.add(theTable, BorderLayout.CENTER);
this.add(theTable);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
}
}
package dmaze2;
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class Dmaze2 extends JPanel
{
JTable jt;
public Dmaze2()
{
String[] columns = {"1","2","3","4","5","6","7","8"};
Object[][] table={{"f","f","f","f","f","f","f","f"},
//if this table is string makes problem to add picture
{"f","f","f","f","f","f","f","f"},
{"f","f","f","f","f","f","f","f"},
{"f","f","f","f","f","f","f","f"},
{"f","f","f","o","f","f","f","f"},
{"f","f","f","f","f","f","f","f"},
{"f","f","f","f","f","f","f","f"},
{"f","f","f","f","f","f","f","f"}};
int num=0;
ImageIcon Icon = new ImageIcon("x.png");
//i have the image in all files of the project to be sure it finds it
for (int i = 0; i < 8 ; i++)
{
int a=1;
for (int j = 0; j<7 && a<8; j++,a++)
{
if(table[i][j]=="f" && table[i][a]=="f")
{
num=num+1;
table[i][j]=Icon;
//if i try to enter the image here it will show it as x.png (as string) instead of the actual picture
table[i][a]="u";
}
}
//int b=1;
for (int j = 0; j<8 && i<7; j++)
{
if(table[i][j]=="f" && table[i+1][j]=="f")
{
num=num+1;
table[i][j]="u";//we put the block used
table[i+1][j]="u";
}
}
System.out.println("");
}
jt = new JTable(table,columns);
{
}
jt.setPreferredScrollableViewportSize(new Dimension(350,363));
jt.setFillsViewportHeight(true);
JScrollPane jps = new JScrollPane(jt);
add(jps);
}
public static void main(String[] args)
{
JFrame jf = new JFrame();
Dmaze2 t = new Dmaze2();
jf.setTitle("Depth First Search");
jf.setSize(500, 500);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
}
}
You need to #Override the getColumnClass() of the table's XxxTableModel. If you don't the renderer will render the column as the Object.toString(). See more at Concepts: Editors and Renderers
DefaultTableModel model = new DefaultTableModel(tableData, columns) {
#Override
public Class<?> getColumnClass(int column) {
switch(column) {
case 1: return ImageIcon.class; // or whichever column you want
default: return String.class;
}
}
};
JTable table = new JTable(model);
Side Notes:
Have a look at How Do I Compare Strings in Java
Set your frame visible after adding all your components
Swing apps should be run on the Event Dispatch Thread. See more at Initial Threads
You may want to read your image files from the class path if the images are resources of your application. Passing a String path to the ImageIcon signifies a read from the local file system. At time of deployment, the path you use will no longer be valid. See the answers from this question and this question for more details on how you can accomplish this task of reading from the class path and embedding your resources.
I have a functionality in a JTable, that when user clicks the cell, it removes certain character in it (like when there's content - Hello, when user clicks it, it shows Hello). When it's no longer edited, it shows - Hello again.
My problem is that when some cell is selected (but not being edited yet) and I start typing Hi, it doesn't remove the character, so the editable cell looks like - Hello Hi.
Same problem is when some cell is selected and user presses space key.
I want to add the functionality to the JTable, so that when the content of the cell starts to be edited (by any way - clicking/typing when selected/space key/and maybe there are more options I don't know about), I want to programatically change the content first. Another option would be removing it when the cell is selected (but then I have to remember position of the last selected cell, so that the character could be readded to it).
I've tried in propertyChange in class TableChangeListener:
table.setValueAt(removeCharacter(table.getValueAt(row,column)), row, column);
but it doesn't work as the cell is already being edited and I cant change it.
You will have to use your own implementation of Cell Editor to meet your own set of requirements.
So create a custom CellEditor implementing FocusLisetener and ActionListener and implement the FocusGained and FocusLost function
Implement the actionPerformed function too to update value on enter click.
Handling the Focus event is a little bit tricky. As it tends to update the cell wrongly. That is why i had to pass the reference table to the CellEditor as a constructor parameter and read the cell row, col on Focus gain.
To reflect the - xxxx: placing - before the cell value, try using a custom CellRenderer. Check out the official tutorial page for details with example. And the part of the credit goes to #mKobel.
An implemented custom cell editor for direction: assign it to your target table column and test.
Giff of my test result:
Code:
class CustomRenderer extends DefaultTableCellRenderer {
public void setValue(Object value)
{
setText("- "+value);
}
}
class MyCellEditor extends AbstractCellEditor
implements TableCellEditor,
FocusListener,
ActionListener
{
JTextField textFeild;
String currentValue;
JTable table;
int row, col;
public MyCellEditor(JTable table) {
this.table = table;
textFeild = new JTextField();
textFeild.addActionListener(this);
textFeild.addFocusListener(this);
}
#Override
public Object getCellEditorValue() {
return currentValue;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
currentValue = (String)value;
return textFeild;
}
#Override
public void focusGained(FocusEvent e) {
textFeild.setText("");
row = table.getSelectedRow();
col = table.getSelectedColumn();
}
#Override
public void focusLost(FocusEvent e) {
if(!textFeild.getText().equals(""))
//currentValue = textFeild.getText();
table.setValueAt(textFeild.getText(), row, col);
fireEditingStopped();
}
#Override
public void actionPerformed(ActionEvent e) {
if(!textFeild.getText().trim().equals(""))
currentValue = textFeild.getText();
fireEditingStopped();
}
}
I think you should not change the content of the cell at all.
What you need is to set on the table a TableCellRenderer that renders the cell values. Implement the cell renderer so that it shows the value "- Hello" (although your actual data could contain just "Hello"). The renderer just shows any component you want in the table. When user starts editing the cell, the renderer component is not shown. Actually you could also manipulate the editing component using a TableCellEditor.
Extracted from this comment:
The table shows prices like "$5" "20€" and when user clicks the cell
to change the price, I'd like the sign to disappear. When user
finishes editing (clicks enter or by other way), I want the symbol to
appear again.
Although #Sage post is a really great and general solution (+1 for you :), in this particular case I'd implement a TableCellRenderer and TableCellEditor using JFormattedTextField which can manage the currency format matter, as follows:
Set a generic number format to the renderer component: NumberFormat.getNumberInstance()
Set a currency number format to the editor component: NumberFormat.getCurrencyInstance()
This way when the cell is displayed the currency sign will be shown but when the cell is being edited the currency sign will "disappear".
Take a look to this example of implementation:
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.text.NumberFormat;
import java.util.EventObject;
import java.util.Locale;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.JFormattedTextField;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.NumberFormatter;
public class CurrencyEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
JFormattedTextField editor;
JFormattedTextField renderer;
Integer clickCountToStart = 2;
public CurrencyEditor(Locale locale) {
initEditor(locale);
initRenderer(locale);
}
private void initRenderer(Locale locale) {
NumberFormat format = locale != null ?
NumberFormat.getCurrencyInstance(locale) : NumberFormat.getCurrencyInstance();
NumberFormatter formatter = new NumberFormatter(format);
formatter.setMinimum(Double.MIN_VALUE);
formatter.setMaximum(Double.MAX_VALUE);
formatter.setAllowsInvalid(false);
renderer = new JFormattedTextField(formatter);
}
private void initEditor(Locale locale) {
NumberFormat format = locale != null ?
NumberFormat.getNumberInstance(locale) : NumberFormat.getNumberInstance();
NumberFormatter formatter = new NumberFormatter(format);
formatter.setMinimum(Double.MIN_VALUE);
formatter.setMaximum(Double.MAX_VALUE);
formatter.setAllowsInvalid(false);
editor = new JFormattedTextField(formatter);
editor.setBorder(UIManager.getBorder("Tree.editorBorder"));
}
#Override
public Object getCellEditorValue() {
return editor.getValue();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if(value instanceof Double){
editor.setValue(value);
}
return editor;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if(value instanceof Double) {
Color background = isSelected ? UIManager.getColor("Table.selectionBackground") : UIManager.getColor("Table.background");
Color foreground = isSelected ? UIManager.getColor("Table.selectionForeground") : UIManager.getColor("Table.foreground");
Border border = hasFocus ? UIManager.getBorder("Table.focusCellHighlightBorder") : BorderFactory.createEmptyBorder();
renderer.setBackground(background);
renderer.setForeground(foreground);
renderer.setBorder(border);
renderer.setValue(value);
return renderer;
} else {
String message = String.format("Not supported for %1$1s class!", value.getClass());
throw new IllegalArgumentException(message);
}
}
}
Disclaimer: it may not work properly with Nimbus look and feel as UIManager properties are named different. I've tested it using Metal, Windows, Windows Classic and Motif.
Here is the code I've used to test it:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.Locale;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Demo {
private void initGUI(){
DefaultTableModel model = new DefaultTableModel(new Object[]{"Item", "Price USD", "Price EUR"}, 0);
model.addRow(new Object[]{"Fender stratocaster", 1599.99d, 1176.46d});
model.addRow(new Object[]{"Gibson Les Paul", 1299.99d, 955.87d});
model.addRow(new Object[]{"Pual Reed Smith Standard 24", 1999.99d, 1470.58d});
JTable table = new JTable(model);
table.setPreferredScrollableViewportSize(new Dimension(500, 300));
TableColumn priceUSD = table.getColumn("Price USD");
priceUSD.setCellRenderer(new CurrencyEditor(Locale.US));
priceUSD.setCellEditor(new CurrencyEditor(Locale.US));
TableColumn priceEUR = table.getColumn("Price EUR");
priceEUR.setCellRenderer(new CurrencyEditor(Locale.GERMANY));
priceEUR.setCellEditor(new CurrencyEditor(Locale.GERMANY));
JPanel content = new JPanel(new BorderLayout());
content.add(new JScrollPane(table));
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().initGUI();
}
});
}
}
Screenshot
I am learning from this oracle tutorial that uses TableDialogEditDemo.java example class
I wrote a custom cell Renderer and Editor for JTable.
I register them to this Oracle TableDialogEditDemo.java class
...
...
//Set up renderer and editor for the Favorite Color column.
table.setDefaultRenderer(Color.class,
new ColorRenderer(true));
table.setDefaultEditor(Color.class,
new ColorEditor());
TableColumn c = table.getColumnModel().getColumn(2);
c.setCellRenderer(new CellStringRenderer()); //My custom Renderer
c.setCellEditor(new CellStringEditor()); // My custom Editor
//Add the scroll pane to this panel.
add(scrollPane);
...
...
(Updated description)
When I click on a cell an input dialogue box pops up and that is OK, and when I type a text and click "OK" the cell in the JTable is updated, but text is not displayed/rendered correctly, I have to click on any other cell to make the text content displayed correctly in the cell.
What is the wrong with my code?.
My Renderer
import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class CellStringRenderer extends JLabel implements TableCellRenderer
{
public CellStringRenderer()
{
this.setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
String stringValue = (String) value;
this.setText(stringValue);
return this;
}
}
My Editor (Updated)
import java.awt.Component;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
public class CellStringEditor extends AbstractCellEditor
implements TableCellEditor
{
String input;
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
if (isSelected)
{
JOptionPane dialog = new JOptionPane();
input = dialog.showInputDialog(null, "new value");
return dialog;
}
return null;
}
#Override
public Object getCellEditorValue()
{
return input;
}
}
I am The author of this question, and I solved it. I will provide the solution so that others can get help from it.
I was trying to write a custom renderer and a custom editor to use with JTable.
The renderer simply uses JLabel to display data. It is already the standard component for JTable.
The editor is a dialogue box that appears when clicking on the cell that I want to edit.
Here is the solution:
The classes that will remain unchanged are the three classes from Oracle + my custom renderer class
1.TableDialogEditDemo.java.
2.ColorEditor.java
3.ColorRenderer.java
4.CellStringRenderer class provided above in the question body (my class)
The class that will be updated is the custom editor class (I changed its name from "CellStringEditor" to "DialogStringEditor"
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class DialogStringEditor extends AbstractCellEditor
implements TableCellEditor,
ActionListener
{
String newInput;
String oldValue;
JButton button;
static final String EDIT = "edit";
public DialogStringEditor()
{
button = new JButton();
button.setBackground(Color.WHITE);
button.setActionCommand(EDIT);
button.addActionListener(this);
button.setBorderPainted(false);
}
#Override
public void actionPerformed(ActionEvent e)
{
if (EDIT.equals(e.getActionCommand()))
{
newInput = JOptionPane.showInputDialog("Edit", oldValue);
if (newInput == null)
{
newInput = oldValue;
}
fireEditingStopped();
}
}
#Override
public Object getCellEditorValue()
{
return newInput;
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column)
{
newInput = (String) value;
oldValue = (String) value;
return button;
}
}
This will work ok
You can also make a little update for the renderer class "CellStringRenderer" to control how are selction and unselection colors of the cell appear.
update this method:
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
String stringValue = (String) value;
this.setText(stringValue);
if (isSelected)
{
this.setBackground(table.getSelectionBackground());
this.setForeground(table.getSelectionForeground());
} else
{
this.setBackground(table.getBackground());
this.setForeground(table.getForeground());
}
return this;
}
}
Regards.