Change behavior of JTable key actions - java

I have a JTable with editable cells. When I click in a cell, it enters edit mode; the same happens when I'm moving through cell using the directional arrows.
Now I want to select the cell instead of start editing, and edit the cell only when the Enter key is pressed.
If any other information is needed, please just ask for it.
Edit: Action for Enter key
class EnterAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
JTable tbl = (JTable) e.getSource();
tbl.editCellAt(tbl.getSelectedRow(), tbl.getSelectedColumn());
if (tbl.getEditorComponent() != null) {
tbl.getEditorComponent().requestFocus();
}
}
}
Now this is for left arrow action the rest of 3 are not hard to deduce from this one:
class LeftAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
JTable tbl = (JTable)e.getSource();
tbl.requestFocus();
tbl.changeSelection(tbl.getSelectedRow(), tbl.getSelectedColumn() > 0 ? tbl.getSelectedColumn()-1:tbl.getSelectedColumn(), false, false);
if(tbl.getCellEditor()!=null)
tbl.getCellEditor().stopCellEditing();
}
}
And this is how you bind this actions:
final String solve = "Solve";
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(enter, solve);
table.getActionMap().put(solve, new EnterAction());
final String sel = "Sel";
KeyStroke arrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(arrow, sel);
table.getActionMap().put(sel, new LeftAction());
Oh,i almost forgot,to select the cell instead of edit on Mouse Click:
public static MouseListener mAdapterTable = new MouseListener()
{
#Override
public void mousePressed(MouseEvent e)
{
JTable tbl=((JTable)e.getComponent());
if(tbl.isEditing())
{
tbl.getCellEditor().stopCellEditing();
}
}
#Override
public void mouseClicked(MouseEvent e) {
JTable tbl=((JTable)e.getComponent());
if(tbl.isEditing() )
tbl.getCellEditor().stopCellEditing();
}
#Override
public void mouseReleased(MouseEvent e) {
JTable tbl=((JTable)e.getComponent());
if(tbl.isEditing() )
tbl.getCellEditor().stopCellEditing();
}
};
The EventListner must be added to table like so:
table.addMouseListener(mAdapterTable);

Use Key Bindings for this. Most Look & Feel implementations already bind F2 to the table's startEditing action, but you add a different binding:
tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "startEditing");
This will effectively replace the previous binding of Enter to the table's selectNextRowCell action.

Here is what i would do:
First enable the single cell selection for the JTable
Create a KeyAdapter or KeyListener for the JTable or for the JPanel,
what contains your table.
In the KeyAdapter's keyPressed() method enter the edit mode of the
selected cell, something like this:
http://www.exampledepot.com/egs/javax.swing.table/StopEdit.html
You can check in the keyPressed() method, if the user pressed the right button for editing. I'm not sure, if the normal (double click) editing is disabled in your table, then what happens, if you try to edit it programmatically, but if it doesn't work, then you can enable the editing on the selected cell, when the user presses the edit button, then when he/she finished, disable it again.

Related

Java Swing: slightly modify existing keyboard behaviour? (right arrow should initially set cursor to position 0)

If a Java Swing JTextField gets the focus, all its text is marked.
Now, I would like to modify the behaviour, so that if the user now presses the right arrow, the cursor should be set to the texts beginning (position 0).
I'm able to get the RIGHT Key event and set the cursor to position 0,
but I don't know how to pass the RIGHT Key event to the original code so that it can handle the normal behaviour.
JTextField preisFieldEUR = new JTextField(…);
AbstractAction right = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if (preisFieldEUR.getSelectionEnd() - preisFieldEUR.getSelectionStart() == preisFieldEUR.getText().length()) {
preisFieldEUR.setSelectionStart(0);
preisFieldEUR.setSelectionEnd(0);
} else {
// Todo: How to pass this event to the original keyboard handler to
// keep the normal behaviour?
}
}
};
preisFieldEUR.getInputMap().put(KeyStroke.getKeyStroke("RIGHT"), right);
Thanks a lot for any help!
You need something like this:
Action oldAction = preisFieldEUR.getActionMap().get("caret-forward"); // probably another parameter?
AbstractAction right = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if (preisFieldEUR.getSelectionEnd() - preisFieldEUR.getSelectionStart() == preisFieldEUR.getText().length()) {
preisFieldEUR.setSelectionStart(0);
preisFieldEUR.setSelectionEnd(0);
} else {
oldAction.actionPeformed(e)
}
}
};

I have a Jtable with a button in one of the columns and I want to access the value in the 1st column when I press the button

I Have a JTable with 3 columns: ID, Name and Operation. In this last column I have a button for every line ( I will post a printscreen ). When I press the button I want to access the value in the first column. I made a listener to the table and it works when I click on the table, but if I click in the button (that is in the 3rd column) it doesn't get the value ( I assume that it is because the click is not directly in the jtable).
How can I get the value when pressing the button?
Thank you
print screen of the JTable function
The listener I made:
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent e) {
if (e.getClickCount() == 1) {
final JTable jTable= (JTable)e.getSource();
final int row = table.getSelectedRow();
final int column = table.getSelectedColumn();
final int valueInCell = (Integer)table.getValueAt(row, 0);
setSelectedID(valueInCell);
System.out.println("Selecionou: "+valueInCell);
}
}
});
Instead of adding regular JButtons to your table you could add your own custom JButton; which would implement ActionListener with the desired behavior when clicked (retrieve data), and at construction time would:
Receive (as an argument) and save the data that you want to reference in a field.
Registers itself as an ActionListener.
Such custom JButton would look like this:
public class DataButton<T> extends JButton implements ActionListener {
private T data;
public DataButton(T data) {
this.data = data;
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
System.out.println("Selection: " + getData());
}
public T getData() {
return data;
}
}

TableModelListener event from keyboard

I Have a Jtable where a TableModelListener is listening
Implemented by
private void anadeListenerAlModelo() {
tabla.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent evento) {
if (evento.getType() == TableModelEvent.UPDATE) {
System.out.println("Editing...");
}
}
});
}
And I want to detect when a cell is being edit but only if is edit from de keyboard, because, other events could update the content.
I only need when the user is editing a cell from the keyboard. It's this posible?
Thanks!
Check out the Table Cell Listener.
It listens for PropertyChange events on the table for when the cell editor is activated/deactivated and then notifies you when the data in the cell has actually been changed.

JTextField.selectAll() works strangely

I'm trying to implement a JTable which has to obey the following rules:
Only the 3'rd column's cells can be edited.
When double clicking any cell in row X, the 3'rd column of row X will start edit.
Whenever start editing a cell, the text inside of it will be selected.
I have a FileTable which extends JTable. In its constructor I have this lines:
getColumnModel().getColumn(2).setCellEditor(new FileTableCellEditor());
addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
if (e.getClickCount() == 2){
int row = rowAtPoint(e.getPoint());
editCellAt(row, 2);
}
}
} );
My FileTableCell editor is as follows:
public class FileTableCellEditor extends DefaultCellEditor {
public FileTableCellEditor() {
super(new JTextField());
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
final JTextField ec = (JTextField) editorComponent;
String textValue = (String)value;
ec.setText(textValue);
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
ec.selectAll();
}
});
return editorComponent;
}
}
My problem is when I double click on a cell which is not from the 3'rd column, The text edited on the 3'rd columns is not highlighted as selected text.
picture http://www.nispahit.com/stack/tableNotHighlight.png
This is very odd to me, because I know the text is selected. When I write something it removes the text that was in that cell before. It just doesn't what is selected.
Oddly, when I double click the 3'rd column cell itself, it does highlight the selection.
picture http://www.nispahit.com/stack/tableHighlight.png
Can someone pour some light?
Thanks!
You can try the Table Select All Editor approach. Don't forget to check out the Table Select All Renderer.
Your JTextField does not highlight the selection because it is not focused. Just add a ec.requestFocus(); right after ec.selectAll();. Then it works as expected.
Explanation: When you click on the editable column Swing will start cell editing (independently of your double-click listener) and forward the initiating event to the component. So the JTextField receives a click and will request focus. When you click on a different column, only your MouseListener initiates cell editing and the event will not get forwarded. (Forwarding the event would not help anyway as the click is outside the text field.) So you have to request the focus manually.

JTable won't listen to Doubleclicks

I´m trying to implement an undo (and redo) function for an editable JTable with the default components. The JTable has an extra class to specify its properties called SpecifiedJTable.
To do so I wanted to grab the moment when a cell is doubleclicked (i.e. the moment when a cell is chosen/marked to be edited) to push the information in the cell and its coordinates onto the stack.
This should be done by a MouseListener ...at least that was my idea.
I tried this (standing in the constructor of my SpecifiedJTable class)
class JTableSpecified extends JTable {
private static final long serialVersionUID = 1L;
private int c; // the currently selected column
private int r; // the currently selected row
public JTableSpecified(String[][] obj, String[] columnNames) {
super(obj, columnNames); // constructs the real table
// makes that you can only select one row at a time
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// makes that columns are not squeezed
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// forbids to rearrange the columns
getTableHeader().setReorderingAllowed(false);
// adds action listener
this.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
r = getSelectedRow();
c = getSelectedColumn();
// get the String at row r and column c
String s = (String) getValueAt(r, c);
if (jobDisplayed) jobSwitch(c, s);
else resSwitch(c, s);
}
});
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println("test");
}
}
});
}
}
but somehow the clickCounter doesn´t want to reach anything that´s higher than 1.
I am glad about any answer and help. Thanks.
The problem you are experiencing is related to use of mouseClicked() rather than using mousePressed(). In this case it appears to be very hard to increase the click counter, yet still it is possible. It took me lots of clicking and also mouse movement to increase the click counter over 1. You could try it by yourself, in your code. To get the counter over 1 you need to go crazy on the mouse by pressing & releasing fast while moving the mouse from cell to cell at the same time (or maybe I was just luckily clicking between the cells?).
As you can see in this fully working sample, made from your code, two mouse presses, using the mousePressed() method are being detected just fine.
public class JTableSpecified extends JTable {
private static final long serialVersionUID = 1L;
public JTableSpecified(String[][] obj, String[] columnNames) {
super(obj, columnNames); // constructs the real table
// makes that you can only select one row at a time
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// makes that columns are not squeezed
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// forbids to rearrange the columns
getTableHeader().setReorderingAllowed(false);
// adds action listener
this.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
}
});
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println("test");
}
System.out.println("e.getClickCount() = " + e.getClickCount());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JPanel panel = new JPanel();
panel.add(new JTableSpecified(new String[][]{{"oi", "oi2"}, {"oi3", "oi4"}}, new String[]{"Col1", "Col2"}));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
f.pack();
f.setVisible(true);
}
});
}
}
Conclusion: Maybe you in fact want to use the mousePressed() method?
This answer extends Boro´s answer.
To catch every case that enables the user to edit the table I will also need to add a KeyListener for F2 (which has the same effect as double clicking onto a cell) and disable the automatic cell editing by pressing any key.
I just added it to the constructor right behind the mouseListener (see above)
// forbids the editing by striking a key
this.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
// keyListener to react on pressing F2 (key code 113)
this.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 113) System.out.println("test");
}
});
The BasicTableUI is responding to the double-click by going into an edit mode on the cell that was double-clicked. It does lots of complicated stuff, part of which involves creating a JTextField (or other component) to allow the data to be edited, and then preventing the mouse click event from propagating any further.
If your table, or that table cell, is not editable, you can easily capture mouse events with click count 2, 3, 4, .... But since you want your table to be editable, you need a different approach.
One idea would be to override JTable.editCellAt()
A better idea is to forget about messing with the JTable and instead listen for data changes on the table model itself.
the error in the code is that the mouseClicked method is called as soon as the first click takes place. when a double click takes place the mouseClicked method is called again. you can place a static variable (or a class variable) for the earlier click event storing the time (using the e.getWhen() method).
Check for the time difference and if it's small enough, execute your actions (I'd suggest calling a doubleClick method).
you may have to implement mouse listener in your class JTableSpecified since a static variable might not be placed in your existing code.

Categories