Set Jtable cell editable ONLY upon selection - java

I have a JTable and I added a DefaultTabelModel to it. I created a popup menu that appears when users right click on a cell in the table. One of the items in the menu is "Rename." How can I make the selected cell editable when the Rename item is clicked? I have set up all the elements and the only missing piece here is making THE selected cell editable.
The isCellEditable(row, col) method in the DefaultTableModel is not helpful here because it sets a cell's editability based on its position (i.e. row and column) in the table, not the selection status of a cell.
I suspect that I will need TableCellEditor, but I am not sure how to use it. I would really appreciate a sample code on how to make this happen and/or explanations of how to use TableCellEditor for this purpose. Thank you in advance!!
Relevant pieces of my code:
class DataListTable extends JTable
mouseReleased():
int row = this.getSelectedRow();
popupmenu.show(this, event.getX(), event.getY());
class RenameDataMenuItem
actionPerformed():
//want to get the (row, col) of the selected cell here and make it editable

How can I make the selected cell editable when the Rename item is clicked?
The isCellEditable(...) method will determine if the cell can be edited via the table editor.
You can still change the data in the model by using the setValueAt(..) method of the JTable or the TableModel.
So what you can do is in your rename menu item you can display a JOptionPane to prompt for the new value. Then you just manually save the value using either of the above methods.

Try something along the lines of this:
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
JComponent component = new JTextField();
#Override
public Object getCellEditorValue() {
return ((JTextField)component).getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if(isSelected) {
((JTextField)component).setText((String)value);
}
return component;
}
}

Related

JComboBox within JTable not saving selection

I have a JTable which contains a Name and Choice column. I would like for the Choice column to contain a JComboBox Component that has the same selection for every row, although allow for independent selection for every unique row.
Currently, interacting with the JComboBox within the column allows for the drop-down to appear for a selection to be made; although, no selection is saved.
Instead, the selection made migrates to any JComboBox that I click on. E.g., I click on the first row's JComboBox and select "Choice B", but all choices still appear as "Choice A". It isn't until I click on another row's JComboBox that the drop-down appears with the "Choice B" selection highlighted.
The code used for this table is as follows:
final String[] choices = new String[]{"Choice A", "Choice B", "Choice C"};
final Collection<String> mockData = Arrays.asList("First", "Second", "Third", "Fourth", "Fifth", "Sixth");
table.setModel(new MasterTableModel(mockData.stream().map(s -> {
return new Object[]{s, new JComboBox<>(choices)};
}).collect(Collectors.toSet())));
table.setDefaultEditor(JComboBox.class, new DefaultCellEditor(new JComboBox<>(choices)));
table.setDefaultRenderer(JComboBox.class, new MasterTableComboRenderer(table.getDefaultRenderer(JComboBox.class)));
I have three choices, which are used to initalize JComboBoxes that populate the Choice column.
I set the DefaultRenderer to my custom MasterTableComboRenderer object which implements the TableCellRenderer interface so as to have the JComboBox show up as a Component rather than to print the address of the object. It only requires the overriding of a single method:
class MasterTableComboRenderer ...
#Override
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
return value instanceof Component ? (Component) value : renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
Finally, MasterTableModel is a simple extension of AbstractTableModel, which defines the column headers [Name, Choice] and holds an Object[][] reperesenting the JTable's data.
I've overriden isCellEditable and getColumnClass as follows:
class MasterTableModel...
#Override
public boolean isCellEditable(final int rowIndex, final int columnIndex) {
return getColumnName(columnIndex).equals("Choice");
}
#Override
public Class<?> getColumnClass(final int columnIndex) {
return getValueAt(0, columnIndex).getClass();
}
Is there something I've been missing to achieve the functionality of the JComboBox saving its choices and not having the selection highlight migrate to other boxes?
A JComboBox should NOT be stored in the TableModel. The String value is stored in the model.
Read the section from the Swing tutorial on Using a Combo Box as a Renderer for a working example.
If you want the renderer to look like a combo box, then you need to use a combo box as a renderer. Something like:
class ComboBoxRenderer extends JComboBox implements TableCellRenderer
{
public ComboBoxRenderer()
{
setBorder(null);
}
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
removeAllItems();
addItem( value );
return this;
}
}

Scrolling inside a JTable cell in Swing

I have a table each cell contains a image. if the image size is more than row height, I have added JScrollPane. Now when I run the application, scroll is visible in each cell but I'm not able to scroll it.
How can I do it?
Below is the code I'm using to add scroll pane.
Any sample code will be appreciated.
private final JTable table = new JTable(model)
{
#Override public Component prepareRenderer(TableCellRenderer tcr, int row, int column)
{
Component c = super.prepareRenderer(tcr, row, column);
if(isRowSelected(row))
{
c.setForeground(getSelectionForeground());
c.setBackground(getSelectionBackground());
}
else{
c.setForeground(getForeground());
c.setBackground((row%2==0)?evenColor:getBackground());
}
JScrollPane _pane=new JScrollPane(c);
table.setRowHeight(100);
return _pane;
}
};
Right click on your jscrollpane
Properties
HOrizontal scrollbarpolicy = always
Vertical scrollbarpolicy = always
To be able to scroll
Right Click on Jtable
Autocreatecolumnfrommodel =false(deactivaded)
In order to be able to set the focus on the cell (so you can use the inside scroll pane), you can get it through "edit mode":
Create a custom cell editor:
public class MyCustomCellEditor extends AbstractCellEditor implements TableCellEditor{
#Override
public Component getTableCellEditorComponent(JTable table,Object value,boolean isSelected,int row,int column) {
JScrollPane your_custom_panel=new JScrollPane();
return your_custom_panel; // your _pane
}
#Override
public Object getCellEditorValue() {
return null;
}
Set it on your table:
table.setDefaultEditor(MyCustomCellValueType.class,new MyCustomCellEditor());
Now you only need to manage how to enter in "edit mode" and you should be able to scroll inside the cell.

Lose Focus and Commit Edit on a JSpinner when clicking outside the spinner

I have a JTable, whose cell editors are JSpinners. I'm using a custom cell editor class to accomplish this. I have a few other components in my JPanel. My problem arises when the user is editing one of the cells (i.e. a JSpinner has focus) and then interacts with one of the other components without first pressing enter or losing focus. I want the JSpinner to immediately lose focus and commit the changes before running the code associated with the other components, but instead the JSpinner just retains its focus.
Ideally, I would like the JSpinner to lose focus immediately whenever the user clicks anywhere but inside the JSpinner itself. Here's my custom editor class:
public class PhyMappingTableCellEditor extends AbstractCellEditor implements TableCellEditor {
final JSpinner spinner = new JSpinner();
public PhyMappingTableCellEditor(ArrayList<String> phys) {
spinner.setModel(new SpinnerListModel(phys));
spinner.setBorder(new EmptyBorder(0,0,0,0));
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
spinner.setValue(value);
return spinner;
}
#Override
public Object getCellEditorValue() {
return spinner.getValue();
}
}
Thanks in advance!
Assuming your custom editor works correctly when you tab from cell to cell then the problem is that you need to manually stop editing on the cell when the table loses focus.
Check out Table Stop Editing. It shows how to stop editing on a cell when the table loses focus. The solution will work for any cell that is being edited, not just your custom editor.
I had a similar problem. If the spinner value was edited using the keyboard and then you clicked another table cell with out first pressing enter, the edits were lost. I solved it by overriding AbstractCellEditor.stopCellEditing() like this:
#Override
public boolean stopCellEditing() {
try {
spinner.commitEdit();
}
catch (ParseException ex) {
// Do nothing
}
return super.stopCellEditing();
}

Button in JTable cell not click-able

I have a jtable with the first column having jbuttons. However when i try to click the button nothing happens. Hovering over the button also doesn't change it's shade to show that it's clickable..
I am running this from within a Java Applet.
I am using the Button Column Class from here:
http://www.camick.com/java/source/ButtonColumn.java
and here is the code i inserted myself
tablemodel = new DefaultTableModel();
//PnlThinClientTable.COLUMNS is an array of strings with the titles of the columns
tablemodel.setColumnIdentifiers(PnlThinClientTable.COLUMNS);
JTable table = new JTable(tablemodel);
table.setEnabled(false);
table.setDefaultRenderer(table.getColumnClass(5), new CustomTblCellRenderer());
table.setBackground(Color.WHITE);
Action wakeUpRow = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e){
JTable table = (JTable)e.getSource();
int modelRow = Integer.valueOf( e.getActionCommand() );
System.out.println("Action Performed");
}
};
// Main.hm_language.get(Language.WAKE_ON_LAN) returns the title of the column i'm interested in
table.getColumn(Main.hm_language.get(Language.WAKE_ON_LAN)).setCellRenderer(new ButtonColumn(table,wakeUpRow,0));
table.getColumn(Main.hm_language.get(Language.WAKE_ON_LAN)).setCellEditor(new ButtonColumn(table, wakeUpRow, 0));
Thanks to #alex2410 for the solution
I had to make sure the cell was Editable
this can be done by either extending the Table upon declaration and overriding the isCellEditable(int row, int col): boolean method,
or in my case I overrode isCellEditable(EventObject e):boolean in the Cell Editor which I apply to the column,
hence the snippet within the Cell Editor I am using would be
#Override
public boolean isCellEditable(EventObject e){
return true;
}
This is as all cells to which the editor is applied need to be editable, as they are all buttons in my case.
Answering to the comment of "how to make 1st column editable" here's how
class MyTableModel extends AbstractTableModel {
public boolean isCellEditable(int row, int col) {
if (col == 1) {
return true;
} else {
return false;
}
}
}
Anyway I leave How to Use Tables Documentation in case it's needed.
And also this post that could help: How to make a table (Jtable) not editable

Pass events in custom JTable

Hi I have a class called ColorChooser (in the net.java.dev.colorchooser.ColorChooser package)
This is a custom component used to select colors. What I want is to display a JTable with ColorChoosers in the second column. So I created my own TableCellRenderer and it works:
#SuppressWarnings("serial")
class ColorChooserTableRenderer extends DefaultTableCellRenderer {
public static List<ColorChooser> colors;
public ColorChooserTableRenderer(int rows) {
colors = new ArrayList<ColorChooser>(rows);
for (int i = 0; i<rows ; i ++) {
colors.add(new ColorChooser());
}
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
return colors.get(row);
}
}
I register this in my table :
JTable t = new JTable(5,3);
t.getColumn(t.getColumnName(1)).setCellRenderer(new ColorChooserTableRenderer(5));
The display is good. It even displays the tool tip of the ColorChoosers when i hover my mouse over one of them. The problem is that the ColorChoosers do not receive MouseEvents.
Normally when you press and hold the mouse on a ColorChooser, you get a pop up window that you can use to select a color. When in the JTable the ColorChooser component does not receive the mouse event.
Any solutions?
Edit: The question can be easily modified to this:
Can you please give me a small example of a table containing JButtons in the second column that actually work? You know, buttons that can be pressed?
This sounds vaguely familiar as I have been using table cell renderers for other purposes.
My understanding is that TableCellRenderer is only used to render the component; a component does not actually exist at each of the cells.
So you'd probably have to somehow forward mouse events from the JTable itself to the ColorChooser.
edit: p.s., see my question -- also for custom table cell rendering, you only need 1 instance of the component itself for the entire column, if the column is rendered with the same logic. Don't store persistent state in the TableCellRenderer, store it in the TableModel instead, and use that state immediately prior to rendering when you handle the call to getTableCellRendererComponent().
A renderer only paints the component on the screen and does not allow for interaction. What you need is to also implement a TableCellEditor. It is recommend that you inherit the AbstractCellEditor and you'll save some work. Check out the java tutorial for tables.
Example:
public class MyTableCellRenderer implements TableCellRenderer
{
private JButton button = new JButton("Press Me");
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
return button;
}
}
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor
{
private JButton button;
public MyTableCellEditor()
{
button = new JButton("Press Me");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("buttonPressed");
}
});
}
public Object getCellEditorValue() {
return null;
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return button;
}
}

Categories

Resources