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.
Related
I'm trying to find a best practise in terms of accessibility on Tables in relation to other components. In an app that's mainly a set of JTables and JTextFields, I tried to make it accessibility with keyboard as well as mouse. My thoughts are on the best way to help the user to navigate around between components using the VK_TAB key.
My first goal was to stop JTables "swallow" the VK_TAB key when the user tries to navigate to a neighbor JTextField using a solution from Coderanch. I tried to put together a minimal compilable and runnable example below.
package TableTest;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
public MyFrame() {
super();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame();
frame.init();
frame.setVisible(true);
}
});
}
private void init() {
JPanel contentPane = new JPanel(new BorderLayout());// new GridBagLayout()
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
JTable table = new JTable(new DefaultTableModel(new Object[][] { { 1, 2, 3 }, //
{ 4, 5, 6 }, //
{ 7, 8, 9 }, //
{ "#", 0, "*" }, }, //
new String[] { "First", "Second", "Third" }));
// When TAB is hit, go to next Component instead of next cell
table.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "tabNext");
table.getActionMap().put("tabNext", new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent ae) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
}
});
// When Shift+TAB is hit, go to previous Component instead of previous cell
table.getInputMap(JComponent.WHEN_FOCUSED)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK), "tabBefore");
table.getActionMap().put("tabBefore", new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent ae) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent();
}
});
JTextField jtf = new JTextField("Text here");
contentPane.add(jtf, BorderLayout.NORTH);
contentPane.add(table, BorderLayout.CENTER);
pack();
}
}
But that's rather radical and frustrating for a user who wants to navigate to a Table cell, e.g. for editing, using only the keyboard. So, my second goal is to give keyboard access to Table Cells as well.
What is a best practise here? I thought of the focussed JTable reacting to VK_ENTER: after that, it would react to VK_TAB by giving focus to the next cell until ... ESC is pressed or whatever.
Thank you!
What is a best practise here?
The default implementation is:
Tab - moves to the next component
Ctrl+Tab - moves to the next component
Shift+Tab - moves to the previous component
Ctrl+Shift+Tab - moves to the previoius component
Some components handle the Tab key. For example:
JTable - tab is used to move to the next cell
Text components (JTextArea, JTextPane) - will insert a Tab character into the text
So for components that handle the Tab key the user would use Ctrl+Tab to navigate to the next component when using the keyboard.
Edit:
I thought of the focussed JTable reacting to VK_ENTER
You already know how to assign a different Action to the Tab key.
So now all you need to do is assign the default Tab Action to the Enter key. You can do this by changing the binding in the InputMap of the Table:
InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
KeyStroke addedKeyStroke = KeyStroke.getKeyStroke("ENTER");
im.put(addedKeyStroke, "selectNextColumnCell");
Check out Key Bindings for a simple app that display all the default Actions for each Swing component.
Thank you, camickr!
So when I change the code following your advice, it works.
That's the complete example:
package TableTest;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
public MyFrame() {
super();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame();
frame.init();
frame.setVisible(true);
}
});
}
private void init() {
JPanel contentPane = new JPanel(new BorderLayout());// new GridBagLayout()
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
JTable table = new JTable(new DefaultTableModel(new Object[][] { { 1, 2, 3 }, //
{ 4, 5, 6 }, //
{ 7, 8, 9 }, //
{ "#", 0, "*" }, }, //
new String[] { "First", "Second", "Third" }));
// When TAB is hit, go to next Component instead of next cell
final KeyStroke tabKey = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(tabKey, "tabNext");
final AbstractAction tabNext = new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent ae) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
}
};
table.getActionMap().put("tabNext", tabNext);
// When Shift+TAB is hit, go to previous Component instead of previous cell
final KeyStroke shiftTabKey = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK);
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(shiftTabKey, "tabBefore");
final AbstractAction tabBefore = new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent event) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent();
}
};
table.getActionMap().put("tabBefore", tabBefore);
// on VK_ENTER, navigate in JTable only ("edit mode")
final KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
final AbstractAction editModeAction = new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent event) {
editMode(table, tabKey, shiftTabKey);
}
};
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(enterKey, "editModeAction");
table.getActionMap().put("editModeAction", editModeAction);
// On VK_ESCAPE or when JTable loses focus, quit the "edit mode"
final KeyStroke escKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
final AbstractAction quitEditModeAction = new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent event) {
quitEditMode(table, tabKey, shiftTabKey);
}
};
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(escKey, "quitEditModeAction");
table.getActionMap().put("quitEditModeAction", quitEditModeAction);
final FocusListener listener = new FocusListener() {
#Override
public void focusGained(FocusEvent event) {
//do nothing
}
#Override
public void focusLost(FocusEvent event) {
quitEditMode(table, tabKey, shiftTabKey);
}
};
table.addFocusListener(listener);
JTextField jtf = new JTextField("Text here");
contentPane.add(jtf, BorderLayout.NORTH);
contentPane.add(table, BorderLayout.CENTER);
pack();
//printActions(table);
}
private void editMode(JTable table, final KeyStroke tabKey, final KeyStroke shiftTabKey) {
System.out.println("editing activated");
table.setCellSelectionEnabled(true);
InputMap input = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
input.remove(shiftTabKey);
input.remove(tabKey);
input.put(shiftTabKey, "selectPreviousColumnCell");
input.put(tabKey, "selectNextColumnCell");
}
private void quitEditMode(JTable table, final KeyStroke tabKey, final KeyStroke shiftTabKey) {
System.out.println("editing de-activated");
table.setCellSelectionEnabled(false);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
InputMap input = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
input.remove(shiftTabKey);
input.remove(tabKey);
input.put(shiftTabKey, "tabBefore");
input.put(tabKey, "tabNext");
}
}
I got the Key bindings to actions from the JTable's ActionMap and InputMap. I tried adding a small method
// print a String representation of each KeyStroke from the InputMap
private void printActions(JTable table) {
InputMap input = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
if (input != null && input.allKeys() != null) {
for (KeyStroke key : input.allKeys()) {
if (key != null) {
printKeyStroke(key);
printActionName(input, key);
}
}
}
}
// build the String represantation
private void printKeyStroke(KeyStroke key) {
StringBuilder tk = new StringBuilder("[");
int modifiers = key.getModifiers();
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0)
tk.append("shift+");
if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0)
tk.append("ctrl+");
if ((modifiers & InputEvent.META_DOWN_MASK) != 0)
tk.append("cmd+");
if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0)
tk.append("alt+");
tk.append("'");
tk.append(KeyEvent.getKeyText(key.getKeyCode()));
tk.append("'=");
tk.append("keycode=");
tk.append(key.getKeyCode());
tk.append("]");
System.out.print(tk.toString());
}
private void printActionName(InputMap input, KeyStroke key) {
System.out.print(": ");
Object string = input.get(key);
if (string != null && string instanceof String)
System.out.println(string.toString());
}
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);
}
});
}});
I have a JTable which can have rows dynamically added by the user. It sits in a JScrollPane, so as the number of rows gets large enough, the scroller becomes active. My desire is that when the user adds a new row, the scroller moves all the way to the bottom, so that the new row is visible in the scrollpane. I'm currently (SSCCE below) trying to use a table model listener to detect when the row is inserted, and force the scrollbar all the way down when the detection is made. However, it seems this detection is "too early," as the model has updated but the new row has not actually been painted yet, so what happens is the scroller moves all the way to the bottom just before the new row is inserted, and then the new row is inserted just below the end of the pane (out of visibility).
Obviously this approach is wrong somehow. What is the correct approach?
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class TableListenerTest {
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel tableModel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TableListenerTest window = new TableListenerTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TableListenerTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
JSplitPane splitPane = new JSplitPane();
frame.getContentPane().add(splitPane);
scrollPane = new JScrollPane();
scrollPane.setPreferredSize(new Dimension(100, 2));
splitPane.setLeftComponent(scrollPane);
tableModel = new DefaultTableModel(new Object[]{"Stuff"},0);
table = new JTable(tableModel);
scrollPane.setViewportView(table);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
scrollBar.setValue(scrollBar.getMaximum());
}
}
});
JButton btnAddRow = new JButton("Add Row");
btnAddRow.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
tableModel.addRow(new Object[]{"new row"});
}
});
splitPane.setRightComponent(btnAddRow);
}
}
EDIT: Updated SSCCE below based on trashgod's request. This version still does not work, however, if I move the scrolling logic from the table model listener to the button listener as he did, then it does work!
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class TableListenerTest {
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel tableModel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TableListenerTest window = new TableListenerTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TableListenerTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
JSplitPane splitPane = new JSplitPane();
frame.getContentPane().add(splitPane);
scrollPane = new JScrollPane();
scrollPane.setPreferredSize(new Dimension(100, 2));
splitPane.setLeftComponent(scrollPane);
tableModel = new DefaultTableModel(new Object[]{"Stuff"},0);
table = new JTable(tableModel);
scrollPane.setViewportView(table);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
int last = table.getModel().getRowCount() - 1;
Rectangle r = table.getCellRect(last, 0, true);
table.scrollRectToVisible(r);
}
}
});
JButton btnAddRow = new JButton("Add Row");
btnAddRow.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
tableModel.addRow(new Object[]{"new row"});
}
});
splitPane.setRightComponent(btnAddRow);
}
}
This example uses scrollRectToVisible() to (conditionally) scroll to the last cell rectangle. As a feature you can click on the thumb to suspend scrolling and release to resume.
private void scrollToLast() {
if (isAutoScroll) {
int last = table.getModel().getRowCount() - 1;
Rectangle r = table.getCellRect(last, 0, true);
table.scrollRectToVisible(r);
}
}
Addendum: I tried scrollRectToVisible in my SSCCE, and it still exhibits the same problem.
This Action provides both mouse and keyboard control:
JButton btnAddRow = new JButton(new AbstractAction("Add Row") {
#Override
public void actionPerformed(ActionEvent e) {
tableModel.addRow(new Object[]{"new row"});
int last = table.getModel().getRowCount() - 1;
Rectangle r = table.getCellRect(last, 0, true);
table.scrollRectToVisible(r);
}
});
Addendum: Here's a variation on your example that illustrates a revised layout strategy.
/** #see https://stackoverflow.com/a/14429388/230513 */
public class TableListenerTest {
private static final int N = 8;
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel tableModel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TableListenerTest window = new TableListenerTest();
window.frame.setVisible(true);
}
});
}
public TableListenerTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.X_AXIS));
tableModel = new DefaultTableModel(new Object[]{"Stuff"}, 0);
for (int i = 0; i < N; i++) {
tableModel.addRow(new Object[]{"new row"});
}
table = new JTable(tableModel) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, table.getRowHeight() * N);
}
};
scrollPane = new JScrollPane();
scrollPane.setViewportView(table);
JButton btnAddRow = new JButton(new AbstractAction("Add Row") {
#Override
public void actionPerformed(ActionEvent e) {
tableModel.addRow(new Object[]{"new row"});
int last = table.getModel().getRowCount() - 1;
Rectangle r = table.getCellRect(last, 0, true);
table.scrollRectToVisible(r);
}
});
frame.add(scrollPane);
frame.add(btnAddRow);
frame.pack();
}
}
However, it seems this detection is "too early,"
For emphasis (#trashgod already mentioned it in a comment): that's true - and expected and a fairly general issue in Swing :-)
The table - and any other view with any model, not only data but also selection, adjustment, ... - is listening to the model to update itself. So a custom listener is just yet another listener in the line (with serving sequence undefined). If it wants to do something that depends on the view state it has to make sure to do so after all internal update is ready (in this concrete context, the internal update includes the update of the adjustmentModel of the vertical scrollBar) Postponing the custom processing until the internals are done, is achieved by wrapping SwingUtilities.invokeLater:
TableModelListener l = new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
invokeScroll();
}
}
protected void invokeScroll() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int last = table.getModel().getRowCount() - 1;
Rectangle r = table.getCellRect(last, 0, true);
table.scrollRectToVisible(r);
}
});
}
};
table.getModel().addTableModelListener(l);
I have a problem with making JComboBox transparent. I tried setting opaque to false and alpha of background 0 but it doesnt work. I guess that i need to change some class that does rendering or something similar.And here is the code..
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.plaf.basic.BasicComboBoxUI;
import java.awt.Color;
public class App {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
App window = new App();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public App() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.getContentPane().setBackground(Color.GREEN);
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
JComboBox comboBox = new JComboBox(petStrings);
comboBox.setBounds(149, 99, 155, 20);
comboBox.setOpaque(false);
//comboBox.setBackground(new Color(0,0,0,0));
((JTextField)comboBox.getEditor().getEditorComponent()).setOpaque(false);
comboBox.setUI(new BasicComboBoxUI(){
public void paintCurrentValueBackground(Graphics g,Rectangle bounds,boolean hasFocus){}});
frame.getContentPane().add(comboBox);
}
}
Assuming you just want the ComboBox's text field transparent (not the popup as well), using the following code should work. You need to mess with the ComboBox renderer instead of the editor. The editor is used for if you can type into the ComboBox; The renderer is used if the ComboBox is a list of values only.
comboBox.setOpaque(false);
comboBox.setRenderer(new DefaultListCellRenderer(){
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JComponent result = (JComponent)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
result.setOpaque(false);
return result;
}});
JComboBox myComboBox = new JComboBox(array);
myComboBox .setOpaque(false);
myComboBox .setEditable(true);
JTextField boxField = (JTextField)myComboBox .getEditor().getEditorComponent();
boxField.setBorder(BorderFactory.createEmptyBorder());
boxField.setBackground(new Color(0, 0, 0, 0));
boxField.setFocusable(false);
The answer is in http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6687960
You need to preset this few things
jcombo.setOpaque(false);
jcombo.setContentAreaFilled(false);
jcombo.setBorderPainted(false);
try this.
yourComboBox.setOpaque(false);
((JTextField)yourComboBox.getEditor().getEditorComponent()).setOpaque(false);
setUI(new BasicComboBoxUI() {
#Override
public void paintCurrentValueBackground(
Graphics g, Rectangle bounds, boolean hasFocus) {
}
});
I'm using ListSelectionListener to update my JTextField (countryTxt) from selected row.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
public class App {
JFrame frame = new JFrame();
JTable table = new JTable();
DefaultTableModel model = new DefaultTableModel(new Object[][] {},
new String[] { "Country", "City", "Street" });
JButton button = new JButton("Remove");
JTextField countryTxt = new JTextField();
int row;
public App() {
table.setModel(model);
data();
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
row = table.getSelectedRow();
countryTxt.setText((String) model
.getValueAt(row, 0));
}
}
});
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
model.removeRow(row);
}
});
frame.add(countryTxt,BorderLayout.NORTH);
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public void data() {
model.addRow(new String[] { "USA", "New York", "First street" });
model.addRow(new String[] { "Russia", "Moscow", "Second street" });
model.addRow(new String[] { "Japan", "Osaka", "Osaka street" });
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new App();
}
});
}
}
But when I select a row and click a button it trows me and ArrayIndexOutOfBounds exception. When I don't select a row in my table and click a button everything works fine. Obviously I can delete a row when valueChanged event is not triggered. So my question is: How to delete a row after valueChanged event is triggered. Thanks in advance.
Have a look at the javadoc of the getLeadSelectionIndex() method
Return the second index argument from the most recent call to setSelectionInterval(), addSelectionInterval() or removeSelectionInterval()
This is not what you expect. You better use the JTable#getSelectedRow() which of course still requires you to check whether it is different from -1 .
A few observations:
Selecting a row via keyboard or mouse updates the countryTxt field correctly.
You can use Control>-Tab to tab out of the table and back to your panel.
Don't use setBounds(); do use pack().
I tested your example without MigLayout, but I don't think that's relevant to your findings.
I had to track down a similar problem involving list removal a while ago. The main issue here is that the button listener's call to model.removeRow(row) was sending a valueChanged event to the model's selection listener, which would then attempt to update the text field using a nonexistent selection (i.e. a list index of -1). I've made these fixes to your code, and the relevant sections are marked with comments. This code allows items to be selected/deleted without throwing an exception.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
public class App {
JFrame frame = new JFrame();
DefaultTableModel model = new DefaultTableModel(new Object[][] {},
new String[] { "Country", "City", "Street" });
JTable table = new JTable(model);
JButton button = new JButton("Remove");
JTextField countryTxt = new JTextField();
public App() {
data();
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
// get the current selected row
int i = table.getSelectedRow();
// if there is a selected row, update the text field
if(i >= 0) {
countryTxt.setText((String) model
.getValueAt(i, 0));
}
}
}
});
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// get the current selected row
int i = table.getSelectedRow();
// if there's no selection, but there are some rows,
// we'll just delete the first row
if(i < 0 && model.getRowCount() > 0) {
i = 0;
}
// if we have a valid row to delete, do the deletion
if(i >= 0) {
countryTxt.setText("");
model.removeRow(i);
table.revalidate();
}
}
});
frame.add(countryTxt,BorderLayout.NORTH);
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public void data() {
model.addRow(new String[] { "USA", "New York", "First street" });
model.addRow(new String[] { "Russia", "Moscow", "Second street" });
model.addRow(new String[] { "Japan", "Osaka", "Osaka street" });
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new App();
}
});
}
}