Some samples I found were modified to try and add padding to the cell using setBorder.
Essentially trying to accomplish the same behavior as setIntercellSpacing but using the BorderFactory class instead.
Based on the following code, there does not appear to be any effect on the cell padding.
What step did I miss?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.DefaultTableCellRenderer;
public class EvenOddRowCellRenderer extends JFrame {
DefaultTableModel tmodel = new DefaultTableModel(new Object[][] { { "some", "text" },
{ "any", "text" }, { "even", "more" }, { "text", "strings" }, { "and", "other" },
{ "text", "values" } }, new Object[] { "Column 1", "Column 2" });
public EvenOddRowCellRenderer() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable table = new JTable(tmodel);
table.setDefaultRenderer(Object.class, new MyRenderer());
getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
pack();
}
public static void main(String arg[]) {
new EvenOddRowCellRenderer().setVisible(true);
}
}
class MyRenderer extends DefaultTableCellRenderer {
public MyRenderer ()
{
super();
setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
JTextField editor = new JTextField();
if (value != null)
editor.setText(value.toString());
editor.setBackground((row % 2 == 0) ? Color.white : Color.cyan);
return editor;
}
}
The default renderer is a JLabel. You are setting the Border on the renderer, which is ok.
The problem is you create a second component, (the text field) and you are returning the JTextField as the renderer component. You didn't add the Border to the text field. Get rid of the JTextField.
Just use return this; to return the label as the renderer.
Related
I want to highlight multiple JTable cells, one by one, then un-highlight or deselect whatever was selected.
The code below is able to highlight one cell at a time.
How do I modify it to be able to do what I need?
I want to deselect by or un-highlight by clicking on a cell itself.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class cellHighlight extends JFrame {
Container container;
JTable table;
JScrollPane pane;
public cellHighlight() {
container = this.getContentPane();
container.setLayout(new BorderLayout());
String[] columnNames = {"First Name", "Last Name", "City", "Branch", "Percent"};
Object[][] rowData = {{"Emma", "Joshua", "New York", "JHY", 67},
{"Ruth", "Gibson", "California", "RE", 95},
{"Mark", "Darwin", "Los Angels", "MNY", 86},
{"Gert", "Mash", "Atlanta", "NBG", 65},
{"Carol", "October", "Memphis", "PIU", 89},
{"Nathan", "Saoirse", "Denver", "SEN", 90}};
table = new JTable(rowData, columnNames);
table.setRowHeight(50);
table.setDefaultRenderer(Object.class, new MyTableRenderer());
pane = new JScrollPane(table);
container.add(pane);
}
public static void main(String[] args) {
cellHighlight frame = new cellHighlight();
frame.setTitle("JTable Example");
frame.setVisible(true);
frame.setSize(700, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyTableRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component c = super.getTableCellRendererComponent(table,
value,
isSelected,
hasFocus,
row,
column);
c.setForeground(Color.WHITE);
if (hasFocus) {
c.setBackground(Color.BLUE);
c.setForeground(Color.WHITE);
c.setFont(new Font("Verdana", Font.BOLD, 16));
}
else {
c.setBackground(Color.WHITE);
c.setForeground(Color.BLACK);
}
return c;
}
}
Any help will be appreciated.
I have a JTable in which one column (Column 1) is a JComboBox that allows options to be made from a list, and to which new options can be entered. MWE:
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.HashSet;
public class ComboTableDemo extends JPanel {
public ComboTableDemo() {
super(new GridLayout(1,0));
final String[] headings = {"Name", "Option"};
final String string1 = "Foo";
final String string2 = "Bar";
Object[][] data = {
{"Albert", string1},
{"Bob", null},
{"Clare", null},
{"David", null}
};
final JTable table = new JTable(data, headings);
table.setPreferredScrollableViewportSize(new Dimension(300, 100));
table.setFillsViewportHeight(true);
final String[] optionsInit = new String[] {string1, string2};
HashSet<String> options = new HashSet<String>(Arrays.asList(optionsInit));
JComboBox<String> optionsCombo = new JComboBox<String>(optionsInit);
optionsCombo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
String newSelection = (String)optionsCombo.getSelectedItem();
if(!options.contains(newSelection)) {
options.add(newSelection);
optionsCombo.addItem(newSelection);
}
}
});
optionsCombo.setEditable(true);
TableColumn column = table.getColumnModel().getColumn(1);
column.setCellEditor(new DefaultCellEditor(optionsCombo));
add(new JScrollPane(table));
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("ComboTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ComboTableDemo pane = new ComboTableDemo();
pane.setOpaque(true);
frame.setContentPane(pane);
frame.pack();
frame.setVisible(true);
}
});
}
}
In the table it isn't obvious that the user can and should enter values for the empty entries, so I'd like to include placeholder text to make this clear. I've seen elsewhere that a custom ListCellRenderer can be provided with setRenderer in the case of uneditable combos, but in the case of editable combos (as explained in the tutorial) it appears that a ComboBoxEditor must be supplied using setEditor. Is there a simple implementation for this, or perhaps even a better way to achieve the same ends?
Actually, input components within a JTable present a special case, since they are only active when the cell is edited. So as well as setting the editor to control how a value is edited, you also need to change the renderer to control how the chosen value is presented, with
// As before:
TableColumn column = table.getColumnModel().getColumn(1);
column.setCellEditor(new DefaultCellEditor(optionsCombo));
// Additional line to set renderer:
column.setCellRenderer(new PlaceholderRenderer("<choose or add option>"));
Here the PlaceholderRenderer should be a TableCellRenderer implementation that displays the placeholder string when no value is selected. E.g.:
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class PlaceholderRenderer extends DefaultTableCellRenderer {
final private String placeholder;
public PlaceholderRenderer(String placeholder) {
super();
this.placeholder = placeholder;
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
if ((value == null) || (value.equals(""))) {
return super.getTableCellRendererComponent(table, this.placeholder, isSelected, hasFocus, row, column);
} else {
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
}
}
How can I set caret position in a JTable?
I know JTextField has setCaretPosition(n) function. But I cannot access JTextField in the JTable.
I would like the Table text caret position equal text length. It is possible to mouseclick event but it should be normal position.
My code:
public class TableTest extends javax.swing.JFrame
{
public TableTest()
{
javax.swing.JTable jTable1 = new javax.swing.JTable();
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object[][]
{
{
"This is too long text!", "This is too long text!",
},
{
"This is too long text!", "This is too long text!",
}
},
new String[]
{
"Title 1", "Title 2",
}
));
add(jTable1);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String args[])
{
new TableTest().setVisible(true);
}
}
This table cells are shown:
[This is too...] but it should be [..long text!]
This table cells are shown: [This is too...] but it should be [..long text!]
This the renderer that displays the text in a cell. The default renderer is a JLabel and it will display ... when the text is truncated. If you want the ... at the start of the cell then you need to create a custom renderer.
Check out the Left Dot Renderer for a renderer that does this.
The default "startEditing" action, suggested here, is provided by BasicTableUI. It typically selects all the text, which you want to avoid. You can invoke setCaretPosition() in a custom Action bound to your preferred keystroke. The example below uses the name "myEditing" and the Space key.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.JTextComponent;
/**
* #see https://stackoverflow.com/a/38051001/230513
*/
public class TableTest {
private void display() {
JFrame f = new JFrame("TableTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model = new DefaultTableModel(
new String[][]{
{"This is too long text!", "This is too long text!",},
{"This is too long text!", "This is too long text!",}
},
new String[]{
"Title 1", "Title 2",}
) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
};
JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(320, 160);
}
};
table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "myEditing");
table.getActionMap().put("myEditing", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
table.editCellAt(table.getSelectedRow(), table.getSelectedColumn());
Component editor = table.getEditorComponent();
if (editor != null) {
editor.requestFocus();
if (editor instanceof JTextComponent) {
JTextComponent jtc = (JTextComponent) editor;
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
jtc.setCaretPosition(jtc.getDocument().getLength());
}
});
}
}
}
});
table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
f.add(new JScrollPane(table));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new TableTest()::display);
}
}
For reference, a similar approach for a mouse event is shown in this previous version.
I have a JTable populated with data from a database. I have added a search function that display the rows, if word matched to some rows when the data is typed into a JTextField. But at the minute as you type a string or word that do not matches any of the rows data, what I want to do is to hide all the rows, and the JTable will show just the column names. Just like when something matches IT, shows those rows only which has the string that user typed and hide others.
Here is my code that I am using:
if (text.length() == 0) {
sorter.setRowFilter(null);
} else {
try {
sorter.setRowFilter(
RowFilter.regexFilter(text));
} catch (PatternSyntaxException pse) {
System.err.println("Bad regex pattern");
}
}
}
You want to use a DocumentListener, along with the row filter. You can see how to Write a DocumentListener.
Basically the listener listens for changes in the underlying document of the text field. From the methods you override in the DocumentListener, you can get the text, like you're currently doing, and set the regex ex filter like you're currently doing
Here's simple example (disregard the applet. I just got the boilerplate code from this post and added the document listener). Note: that same post has an answer provided that will allow you to filter in a case-insensitive way, if you're looking for that functionality
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TestTableSorterFilter extends JApplet {
private String[] columnNames
= {"Country", "Capital", "Population in Millions", "Democracy"};
private Object[][] data = {
{"USA", "Washington DC", 280, true},
{"Canada", "Ottawa", 32, true},
{"United Kingdom", "London", 60, true},
{"Germany", "Berlin", 83, true},
{"France", "Paris", 60, true},
{"Norway", "Oslo", 4.5, true},
{"India", "New Delhi", 1046, true}
};
private JTable jTable = new JTable(data, columnNames);
private TableRowSorter<TableModel> rowSorter
= new TableRowSorter<>(jTable.getModel());
private JTextField jtfFilter = new JTextField();
private JButton jbtFilter = new JButton("Filter");
public TestTableSorterFilter() {
jTable.setRowSorter(rowSorter);
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JLabel("Specify a word to match:"),
BorderLayout.WEST);
panel.add(jtfFilter, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
add(new JScrollPane(jTable), BorderLayout.CENTER);
jtfFilter.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent arg0) {}
#Override
public void insertUpdate(DocumentEvent arg0) {
String text = jtfFilter.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter(text));
}
}
#Override
public void removeUpdate(DocumentEvent arg0) {
String text = jtfFilter.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter(text));
}
}
});
}
}
I would like to have a jtable with 4 columns.
One column must be a combobox.
Other columns are strings.
When i click one time on a cell, i would like the cell become editable with blinking caret/cursor.Also, if i click on the combobox i would like the combox set popup visble.
I have read and tested tutorial "How to Use Tables", and if i make just one click on combobox in the cell, it opens. My first problem is that i don't understand why the code in the tutorial works when we implement abstract table model and not working DefaultTableModel.
My code is :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class JtabletestOK {
public static void main(String[] args) {
JtabletestOK test = new JtabletestOK();
test.go();
}
public void go() {
//create the frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create a table and add it to a scroll pane in a new tab
JTable jTable1 = new JTable()
{
// Place cell in edit mode when it 'gains focus'
public void changeSelection(
int row, int column, boolean toggle, boolean extend)
{
super.changeSelection(row, column, toggle, extend);
if (editCellAt(row, column))
{
Component editor = getEditorComponent();
editor.requestFocusInWindow();
// System.out.println("ffin focus gagne");
if (editor instanceof JTextField) {
JTextField jf = (JTextField) editor;
jf.select(0, jf.toString().length());
}}
}
};
jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
jTable1.setFillsViewportHeight(true);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(jTable1);
Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4" };
DefaultTableModel model = new DefaultTableModel(columnNames, 0);
Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
model.addRow(rowData);
jTable1.setModel(model);
String[] comboBoxArray = {"proem1","veitem2","atem3"};
JComboBox jcb = new JComboBox(comboBoxArray);
jcb.setEditable(true);
TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
colCombo.setCellEditor(new DefaultCellEditor(jcb));
jcb.setEditable(true);
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setVisible(true);
}
The source with abstract model is here :
http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableRenderDemoProject/src/components/TableRenderDemo.java
Just find the problem : When commenting the statement jcb.setEditable(true); , if i do a single click on the comboxcell it opens the cell.
But i don't know why it works better. Also, i would like the combox editable.
How i can have the same behavior for others cells.
Hello again, i have updated the code in order to have
- cells become editable if i click one time on the cell by overriding the method
- combobox become editable if i click one time on the cell by overriding the method
I put my new code here, it may help other :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;
public class JtabletestOK {
public static void main(String[] args) {
JtabletestOK test = new JtabletestOK();
test.go();
}
public void go() {
//create the frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create a table and add it to a scroll pane in a new tab
JTable jTable1 = new JTable()
{
// Place cell in edit mode when it 'gains focus'
public void changeSelection(
int row, int column, boolean toggle, boolean extend)
{
super.changeSelection(row, column, toggle, extend);
if (column > 0)
{
if (editCellAt(row, column))
{
Component editor = getEditorComponent();
editor.requestFocusInWindow();
// System.out.println("ffin focus gagne");
if (editor instanceof JTextField) {
JTextField jf = (JTextField) editor;
jf.select(0, jf.toString().length());
}}
}
}
};
jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
jTable1.setFillsViewportHeight(true);
replaceTabByEnter(jTable1);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(jTable1);
Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4" };
DefaultTableModel model = new DefaultTableModel(columnNames, 0);
Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
model.addRow(rowData);
jTable1.setModel(model);
String[] comboBoxArray = {"proem1","veitem2","atem3"};
JComboBox jca = new JComboBox(comboBoxArray);
jca.setSelectedItem("");
JTextComponent editor = (JTextComponent) jca.getEditor().getEditorComponent();
jca.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
JComponent ja = (JComponent) e.getSource();
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
JComponent ja = (JComponent) e.getSource();
JTable jtb = (JTable) ja.getParent();
jtb.changeSelection(0,1,false,false);
}
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
editor.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Not mouseClicked yet.");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("Not mousePressed yet.");
}
#Override
public void mouseReleased(MouseEvent e) {
JComponent ja = (JComponent) e.getSource();
JComponent jcbloc = (JComponent) ja.getParent();
JComboBox jcb = (JComboBox) jcbloc;
jcb.setPopupVisible(true);
System.out.println("Not mouseReleased yet.");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("Not mouseEntered yet.");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("Not mouseExited yet.");
}
});
autocompletecombo jcb =new autocompletecombo(jca);
TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
jca.setEditable(true);
comboboxEditor cbe = new comboboxEditor(jca);
colCombo.setCellEditor(cbe);
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setVisible(true);
}
public void replaceTabByEnter(JTable jtane) {
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
InputMap im = jtane.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(enter, im.get(tab));
}
class comboboxEditor extends AbstractCellEditor implements TableCellEditor{
JComboBox comboBox;
JTextField jtf;
S11InitialSelection sjcb;
#Override
public Object getCellEditorValue() {
return comboBox.getSelectedItem();
}
public comboboxEditor(JComboBox jcb) {
comboBox = jcb;
jtf.selectAll();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
comboBox.setSelectedItem(value);
return comboBox;
}
public boolean stopCellEditing() {
fireEditingStopped();
// jt.EditNextCell();
return true;
}
}
}
When i click on the combobox i would like to highlight the text by selecting it.
I don't remember how to get the textfield from the jcombobox in order to use selectAll() method or something like that.
I have find a solution for that :
public void mouseReleased(MouseEvent e) {
JComponent ja = (JComponent) e.getSource();
JComponent jcbloc = (JComponent) ja.getParent();
JComboBox jcb = (JComboBox) jcbloc;
jcb.setPopupVisible(true);
JTextComponent editor = (JTextComponent) jcb.getEditor().getEditorComponent();
editor.setSelectionStart(0);
editor.setSelectionEnd(editor.getText().length());
System.out.println("Not mouseReleased yet.");
}
Thanks for your help.
I have finally find how to solve all my problems. I post all the code.
I hope it will help others. If you find better way to adress the problem, i'm open.
It remains two strange thing but it work as i want, so if somenone as an idea :
If i move the code
if(e.getKeyChar() == KeyEvent.VK_ENTER){
JComponent ja = (JComponent) e.getSource();
JComboBox jcbloc = (JComboBox) ja.getParent();
JTable jtb = (JTable) jcbloc.getParent();
jtb.changeSelection(0,1,false,false);
}
in keyReleased instead of keyPressed, it doesn't work.
When i press enter on basic cell text, the program go to next cell alone. I don't understand how it goes alone to next cell on enter key.
All the code here :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.basic.BasicTextUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;
public class JtabletestOKStackOver {
public static void main(String[] args) {
JtabletestOKStackOver test = new JtabletestOKStackOver();
test.go();
}
public void go() {
//create the frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create a table and add it to a scroll pane in a new tab
JTable jTable1 = new JTable()
{
// Place cell in edit mode when it 'gains focus'
public void changeSelection(
int row, int column, boolean toggle, boolean extend)
{
super.changeSelection(row, column, toggle, extend);
if (column > -1)
{
if (editCellAt(row, column))
{
Component editor = getEditorComponent();
editor.requestFocusInWindow();
if (editor instanceof JTextField) {
JTextField jf = (JTextField) editor;
jf.select(0, jf.toString().length());
}
if (editor instanceof JComboBox) {
JComboBox jcb = (JComboBox) editor;
jcb.setPopupVisible(true);
JTextComponent editorCombo = (JTextComponent) jcb.getEditor().getEditorComponent();
editorCombo.setSelectionStart(0);
editorCombo.setSelectionEnd(editorCombo.getText().length());
}
}
}
}
};
jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
jTable1.setFillsViewportHeight(true);
jTable1.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(jTable1);
Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4" };
DefaultTableModel model = new DefaultTableModel(columnNames, 0);
Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
model.addRow(rowData);
jTable1.setModel(model);
String[] comboBoxArray = {"proem1","veitem2","atem3"};
JComboBox jca = new JComboBox(comboBoxArray);
jca.setSelectedItem("");
JTextComponent editor = (JTextComponent) jca.getEditor().getEditorComponent();
editor.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyChar() == KeyEvent.VK_ENTER){
JComponent ja = (JComponent) e.getSource();
JComboBox jcbloc = (JComboBox) ja.getParent();
JTable jtb = (JTable) jcbloc.getParent();
jtb.changeSelection(0,1,false,false);
}
}
#Override
public void keyReleased(KeyEvent e) {
}
});
editor.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
JComponent ja = (JComponent) e.getSource();
JComponent jcbloc = (JComponent) ja.getParent();
JComboBox jcb = (JComboBox) jcbloc;
jcb.setPopupVisible(true);
JTextComponent editor = (JTextComponent) jcb.getEditor().getEditorComponent();
editor.setSelectionStart(0);
editor.setSelectionEnd(editor.getText().length());
}
#Override
public void focusLost(FocusEvent e) {
}
});
TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
jca.setEditable(true);
comboboxEditor cbe = new comboboxEditor(jca);
colCombo.setCellEditor(cbe);
TableColumn colAutre = jTable1.getColumnModel().getColumn(1);
TableColumn colAutre2 = jTable1.getColumnModel().getColumn(2);
TableColumn colAutre3 = jTable1.getColumnModel().getColumn(3);
textCellEditor dce = new textCellEditor(new JTextField());
colAutre.setCellEditor(dce);
colAutre2.setCellEditor(dce);
colAutre3.setCellEditor(dce);
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setVisible(true);
}
class comboboxEditor extends AbstractCellEditor implements TableCellEditor{
JComboBox comboBox;
public comboboxEditor(JComboBox jcb) {
comboBox = jcb;
}
public Object getCellEditorValue() {
return comboBox.getSelectedItem();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
comboBox.setSelectedItem(value);
return comboBox;
}
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
}
class textCellEditor extends AbstractCellEditor implements TableCellEditor{
JTextField jtextfield;
public textCellEditor(JTextField jtf) {
jtextfield = jtf;
}
public Object getCellEditorValue() {
return jtextfield.getText();
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (isSelected) {
// cell (and perhaps other cells) are selected
}
if (value== null)
{
value="";
}
value = value.toString();
if (value instanceof Integer) {
value = value.toString();
}
jtextfield.setText((String) value);
// Return the configured component
return jtextfield;
}
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
}
}
Thanks for your help.
Don't use an ActionListener on the combo box. The "popup" will be displayed by the editor when you click on the cell.
My first problem is that i don't understand why the code in the tutorial works when we implement abstract table model and not working DefaultTableModel.
Editing is controlled by the isCellEditable(...) method of the TableModel. When you click on a cell that is editable the JTable will use the appropriate editor. If the editor is a combo box, then the popup will be displayed when the cell is clicked.
Just find the problem : When commenting the statement jcb.setEditable(true); , if i do a single click on the comboxcell it opens the cell. But i don't know why it works better
When you click on a cell I believe the MouseEvent is forwarded to the editor (ie the combo box). Since the combo box is editable the MouseEvent goes to the text field, so focus remains of the text field and the popup is not displayed. Try this with a normal combo box, not displayed in a JTable so see the same behaviour.
I don't know why your code with AbstractTableModel works (because I cannot see it). But I can help you to make your example working.
jcb.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
System.out.println("test");
final JComboBox j= (JComboBox)evt.getSource();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (j.isDisplayable()) j.setPopupVisible(true);
}
});
}});