Swing - JTable, CellEditors and terminateEditOnFocusLost

D

dbaldes

Hello,

I have a JTable with some custom editors. I set the
"terminateEditOnFocusLost" property to have editors get removed
properly when the user "leaves" the table. The problem arises when the
user is editing a cell of the table and then clicks on another cell to
edit that one:

- editing of the cell currently being edited is stopped (good)
- the editor of the new cell is loaded (getEditorComponent called)
(good)
- JTable loses focus for some reason to somewhere (probably bad)
- JTable stops editing of the newly clicked cell (due to
terminateEditOnFocusLost i guess) (bad)

So the user has to click a second time on the new cell to edit it,
cause the editor was stopped right after being loaded on the first
click..

Without "terminateEditOnFocusLost" the behaviour is also strange: on
most Editors (simple text fields f.e.) it works well (problem described
above does not arise) , but on a custom ComboBox editor the combobox
pops up and closes again on the first click, BUT only when the cell
editor used before was also the combobox editor.. so the user has to
click a second time on the combobox to get the drop down list. When the
user was editing another column (with other editor) before, the
combobox pops up its drop down list and stays open on the first click
as I expect it to.

What i want is: 1. the behaviour of terminateEditOnFocusLost without
editors being removed when i click to edit a cell and 2. the combobox
to pop up and stay open on 1st click in any case

I already tried overriding "shouldSelectCell" in the editors (which is
not called any more, i read somewhere) because I suspected it to be
related to focusing, and messing around with JTable.requestFocus, and
the "focusable" property of the JTable is true - I did not get it to
work properly up to now.

Can you help me with this problem?

Thanks in advance!

Regards,
Daniel
 
Z

zero

Hello,

I have a JTable with some custom editors. I set the
"terminateEditOnFocusLost" property to have editors get removed
properly when the user "leaves" the table. The problem arises when the
user is editing a cell of the table and then clicks on another cell to
edit that one:

- editing of the cell currently being edited is stopped (good)
- the editor of the new cell is loaded (getEditorComponent called)
(good)
- JTable loses focus for some reason to somewhere (probably bad)
- JTable stops editing of the newly clicked cell (due to
terminateEditOnFocusLost i guess) (bad)

So the user has to click a second time on the new cell to edit it,
cause the editor was stopped right after being loaded on the first
click..

Without "terminateEditOnFocusLost" the behaviour is also strange: on
most Editors (simple text fields f.e.) it works well (problem described
above does not arise) , but on a custom ComboBox editor the combobox
pops up and closes again on the first click, BUT only when the cell
editor used before was also the combobox editor.. so the user has to
click a second time on the combobox to get the drop down list. When the
user was editing another column (with other editor) before, the
combobox pops up its drop down list and stays open on the first click
as I expect it to.

What i want is: 1. the behaviour of terminateEditOnFocusLost without
editors being removed when i click to edit a cell and 2. the combobox
to pop up and stay open on 1st click in any case

I already tried overriding "shouldSelectCell" in the editors (which is
not called any more, i read somewhere) because I suspected it to be
related to focusing, and messing around with JTable.requestFocus, and
the "focusable" property of the JTable is true - I did not get it to
work properly up to now.

Can you help me with this problem?

Thanks in advance!

Regards,
Daniel

Do you have an online example that we could experiment with, and a short,
compilable example (see http://www.mindprod.com/jgloss/sscce.html)
 
D

dbaldes

Hi,

"unfortunately" i did not manage to reproduce the odd behaviour with
the editors being removed im my sscce, but the combobox problem
(described in paragraph "Without terminateEditOnFocusLost") arises here
(with and without that property set). I will further investigate and
try to reproduce the problem with editors being removed; In the
meantime the following serves as sample for the ComboBox problem (which
might be in some way related to the editors-being-removed-problem).

How to reproduce the problem with the sample code:

1. click on cell with "ab" in it
-> combobox appears and pops open
2. select some value
-> combobox closes its dropdown and displays new value
3. click on cell with "bb" in it
-> new combobox appears, but is closed
(i do not see the box pop open and close again; i think it is due to
the example
running faster due to the rather simple list content)

Whenever the combobox editor is active, clicking on another cell with
the combobox editor gives the described behaviour. When another or no
editor is active, the combobox pops open as it is supposed to.

any help is greatly appreciated.

---8X-------------------------------------
import java.awt.BorderLayout;
import java.awt.Component;

import javax.swing.*;
import javax.swing.table.TableCellEditor;

public class TestMain {

public static void main(String[] args) {
JTable table = new JTable(
new String[][] { { "aa", "ab" }, { "ba", "bb" } },
new String[] { "A", "B"} );
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

table.getColumnModel().getColumn(1).setCellEditor(
new CustomEditor());

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(table, BorderLayout.CENTER);
frame.getContentPane().add(new JTextField(), BorderLayout.SOUTH);
frame.setSize(400,300);
frame.setVisible(true);
}

private static class CustomEditor
extends AbstractCellEditor
implements TableCellEditor {

private JComboBox cbComponent;

public CustomEditor() {
cbComponent = new JComboBox(new String[] { "xx", "yy", "zz" } );
}

public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
return cbComponent;
}

public Object getCellEditorValue() {
return cbComponent.getSelectedItem();
}
}
}
 
D

dbaldes

Hi again,

I just managed to reproduce the problem. The difference of the
following code to the example above is that the ComboBox is inside a
JPanel, and the JPanel is returned as editor (i do this to get the
combobox centered vertically in higher rows in my application).

Repeat the steps in the posting before to reproduce the problem:
Clicking on a combobox cell (here the rightmost column) when a ComboBox
is already open results in the new editor being loaded, stopped and
removed immediately.

Maybe the Table passes focus to the JPanel, the panel then passes focus
to the ComboBox and the JTable then deems the focus to be lost?

------8X-----------------------------------
import java.awt.BorderLayout;
import java.awt.Component;

import javax.swing.*;
import javax.swing.table.TableCellEditor;

public class TestMain {


public static void main(String[] args) {

JTable table = new JTable(
new String[][] { { "aa", "ab" }, { "ba", "bb" } },
new String[] { "A", "B"} );
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

table.getColumnModel().getColumn(1).setCellEditor(
new CustomEditor());

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(table, BorderLayout.CENTER);
frame.getContentPane().add(new JTextField(), BorderLayout.SOUTH);
frame.setSize(400,300);
frame.setVisible(true);
}

private static class CustomEditor
extends AbstractCellEditor
implements TableCellEditor {

private JPanel panel;
private JComboBox cbComponent;

public CustomEditor() {
panel = new JPanel(new BorderLayout());
cbComponent = new JComboBox(new String[] { "xx", "yy", "zz" } );
panel.add(cbComponent, BorderLayout.CENTER);
}

public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
return panel;
}

public Object getCellEditorValue() {
return cbComponent.getSelectedItem();
}
}
}
 
V

Vova Reznik

dbaldes said:
private static class CustomEditor
extends AbstractCellEditor
implements TableCellEditor {

Did you find that your CustomEditor implements CellEditor twice?
As sub of AbstractCellEditor and sub of TableCellEditor.

Try this:
private static class CustomEditor extends DefaultCellEditor {

private JPanel panel;
private static final JComboBox cbComponent = new JComboBox(new
String[] { "xx", "yy", "zz" });

public CustomEditor() {
super(cbComponent);
panel = new JPanel(new BorderLayout());
panel.add(cbComponent, BorderLayout.CENTER);
}

public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
return panel;
}

public Object getCellEditorValue() {
return cbComponent.getSelectedItem();
}
}
 
D

dbaldes

Hi,

it does not implement it twice. AbstractCellEditor implements
CellEditor, and my Subclass implements remaining methods of
TableCellEditor. This works well and is not related to the problem.
Your code does not change the behaviour (it just adds useless
functionality to the editor).
 
Z

zero

Clicking on a combobox cell (here the rightmost column) when a ComboBox
is already open results in the new editor being loaded, stopped and
removed immediately.

Ok, I think I have an acceptable solution.

Your main problem is that the editing is never actually stopped, because
your CustomEditor never calls fireEditingStopped. You could add this in an
itemListener or actionListener on the combo box, but those both have flaws
(specifically when opening and closing the combo box without changing the
selected value). The solution is to use a PopupMenuListener.

Add this to CustomEditor's constructor:

cbComponent.addPopupMenuListener(new PopupMenuListener()
{
public void popupMenuCanceled(PopupMenuEvent e)
{
fireEditingCanceled();
}

public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
{
fireEditingStopped();
}

public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
}
});

This code will cancel or stop the editing when appropriate.

I believe you don't need the terminateEditOnFocusLost property, but do some
testing to be sure.
 
Z

zero

Your main problem is that the editing is never actually stopped,
because your CustomEditor never calls fireEditingStopped.

btw, all these problems are caused by the fact that you use the same
CustomEditor for every cell in the column, and this CustomEditor re-uses
the same JComboBox. If you would have a separate instance of CustomEditor
for each cell, or recreate the JComboBox, I think you would have far less
problems. But of course this does use more memory.
 
D

dbaldes

Hi,

the default implementation of AbstractCellEditor calls
fireEditingStopped() (and cancelled). My "true" application does it
itself. (on stopCellEditing/cancelCellEditing, which is called by the
table implementation; those methods are called when i leave the editing
cell)
Reusing Components is the intention of the whole
TableCellEditor/Renderer model, i think..

But your code resolved the problem for me, so thanks a lot!

Regards,
Daniel
 
D

dbaldes

Hi, erm, wait,

it solves the problem for my combobox editors, which is a great step in
the right direction, but... I also have other editos (textfield,
lists..), so if anyone knows a more general solution I would be glad.

I'll try to add listeners and call fireEditingStopped/Cancelled myself,
but I think there should be a way which works with the default
behaviour (table implementation calls editor.stopCellEditing(), editor
calls fireEditingStopped() ..)

thanks in advance..

Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top