I need to override the enter key functionality on a JTable. At present the default behaviour is to move the row selection down one row when the user presses the 'Enter' key. I want to disable this and get it to do something different based on their selection. The problem is that it seems to move down before it goes into my keylistener which takes in the row selection - this therefore opens another window with the wrong row selected.
This is my code so far...:
public class MyJTable extends JTable {
public MyJTable(){
setRowSelectionAllowed(true);
addListeners()
}
public void addListeners(){
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
openChannel();
}
}
});
}
public void openChannel(){
for (int selectedRow : getSelectedRows()){
//Code to open channel based on row selected
}
}
}
+1 to #Robin's answer
Adding to my comment...
Swing uses KeyBindings simply replace exisitng functionality by adding a new KeyBinding to JTable (the beauty happens because of JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT):
private void createKeybindings(JTable table) {
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
table.getActionMap().put("Enter", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
//do something on JTable enter pressed
}
});
}
simply call this method and pass JTable instance to override standard functionality of JTable ENTER
This is implemented using key bindings, which is preferred over key listeners. I strongly suggest you do the same: replace your key listener by a key binding.
The solution is replace the entry in the InputMap to point to your own Action (which you insert in the action map), or to just replace the appropriate entry in the action map.
The key bindings tutorial contains more info
Related
The problem
In Swing (Java), I want to capture all keyboard input, regardless of which control has focus.
So, if I press a key on my keyboard (not just alphanumeric, function keys and such included), while the window is in focus, a callback should run, allowing me to do what I want with the given input.
What I've tried
Using the panel I've tried to add a key listener, which implements the KeyListener class in java.awt.event, like so:
// MainApplicationWindow.java
// ...
mPanel.addKeyListener(
new SwingKeyListener()
);
With the actual listener being:
// SwingKeyListener.java
public class SwingKeyListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {/*...*/}
#Override
public void keyPressed(KeyEvent e) {/*...*/}
#Override
public void keyReleased(KeyEvent e) {/*...*/}
}
Results
GUI is displayed, no errors or exceptions are outputted, key listener does not work.
Solutions
Solution was to use the KeyEventPostProcessor class to poll for input.
KeyEventPostProcessor pp = e -> {
SwingKeyListener.keyPressed(e);
return true;
};
DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(pp);
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.
I have a JButton that has action listener.
btn_.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// DO STUFF
}
}
And I have a JSpinner that listens for key events.
spn_.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
System.out.println("Someone pressed enter key");
}
}
});
What I would like to do, is whenever user presses enter key while the spinner is selected, I would like it to execute whatever command the button does.
Yes I understand that I can simply have a function for the actions button does, and then execute the same function when user presses enter key. I am asking this because I am curious if it is possible for components in Swing to send actions to each other and how to do it rather than what is the correct way to program.
Yes I understand that I can simply have a function for the actions button does, and then execute the same function when user presses enter key. I am asking this because I am curious if it is possible for components in Swing to send actions to each other and how to do it rather than what is the correct way to program.
If you are implying that executing a function is the correct way, I would suggest that is not the best way to solve the problem.
The correct way is to share the Action, not the method that you invoke.
You should NOT be using a KeyListener at all in this solution. The general solution is to use Key Bindings. Read the Swing tutorial on How to Use Key Bindings for more information.
However, in your case it is even a little easier because you can just share the ActionListener:
ActionListener al = new ActionListner() {...}
JTextField editor = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
editor.addActionListener(al);
button.addActionListener(al);
Use doClick() method of JButton:
btn_.doClick()
Within keyPressed as following:
spn_.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
btn_.doClick()
}
}
});
The doClick() method as specified in oracle doc:
Programmatically perform a "click". This does the same thing as if the
user had pressed and released the button.
spn_.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
btn_.doClick(); // fires the actionPerfomed on the button
}
}
});
I have a JTable that has a delete button to delete its rows.
I want to create a shortcut, for example when user selects a row and presses the 'Delete' button on keyboard , that line should be deleted.
My line is deleted with my JButton1 perfectly.
if (e.getSource() == KeyEvent.VK_DELETE) {
// Delete row Method
}
But it doesn't work.
don't to use KeyListener for this job, and in Swing never, use KeyBindings instead
add ListSelectionListener to JTable, notice to test if(table.getSelectedRow > 0)
use KeyBindings for JTable, override Delete key
I don't know what is the exact problem because you provide too few code. However, you can't use getSource() to test which key is typed (pressed, or released). Use getKeyChar() and getKeyCode().
The following is explanation of my code:
You need to add a KeyListener to a component(of course)
The component must have focus
The component must be focusable (set focusable to true)
The component need to request for focus
Override keyTyped keyPressed or keyReleased to retrieve KeyEvent
To check which key is typed in keyTyped, use getKeyChar()
To check which key is pressed or released in keyPressed and keyReleased, use getKeyCode()
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Test {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(new Dimension(410, 330));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBackground(Color.GREEN);
panel.setBounds(50, 50, 300, 200);
panel.addKeyListener(new MyKeyListener()); // add KeyListener
panel.setFocusable(true); // set focusable to true
panel.requestFocusInWindow(); // request focus
f.getContentPane().add(panel);
f.setVisible(true);
}
static class MyKeyListener extends KeyAdapter {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == '\177') {
// delete row method (when "delete" is typed)
System.out.println("Key \"Delete\" Typed");
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
// delete row method (when "delete" is pressed)
System.out.println("Key \"Delete\" Pressed");
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
// delete row method (when "delete" is released)
System.out.println("Key \"Delete\" Released");
}
}
}
}
Take a look to this page:
http://www.coderanch.com/t/341332/GUI/java/setting-keyboard-navigation-shortcut-keys
Taken from there:
Create a key listener for that button (it seems you have already made that):
Button btn = new Button("Press Me");
btn.addKeyListener(myKeyListener);
And implement the keylistener:
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_DELETE ){
//Do whatever you want
}
}
Try it and tell me if it works.
JTable cells by default are in append mode when the cell is double clicked on.
Is there a way to make the cell default to overwrite mode instead, IOW, select the contents of the cell so that if the user started typing the old text would be replaced by the new text without having to manually erase it?
You should be able to do this by creating your own TableCellEditor, which can be assigned to the parent table using setCellEditor(). This object is a factory that is called by the JTable whenever the user starts editing a cell, to create the field used to do the actual editing. You can return your own JTextField, and simply avoid setting the old value to achieve what your asking. You'll also have to attach a listener to the text field to update the value in the table when the user has finished typing.
You might find the Table Select All Editor helpful.
I have implemented the following method [addDeletePreviousOnEditBehavior] that works fine! Note that you need to use some TableCellEditor. To do so add the following code:
JTable table=new JTable();
JTextField field=new JTextField();
addDeletePreviousOnEditBehavior(field);
table.setCellEditor(new DefaultCellEditor(field));
The method is:
public static void addDeletePreviousOnEditBehavior(final JComponent field) {
field.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent fe) {
field.putClientProperty(DELETE_ON_EDIT, true);
}
#Override
public void focusLost(FocusEvent fe) {
}
});
field.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent ke) {
}
#Override
public void keyPressed(KeyEvent ke) {
if ((!(ke.isActionKey()
|| isSpecial(ke.getKeyCode())))
&& ((Boolean) field.getClientProperty(DELETE_ON_EDIT))) {
System.out.println("Key:" + ke.getKeyCode() + "/" + ke.getKeyChar());
field.putClientProperty(DELETE_ON_EDIT, false);
if (field instanceof JFormattedTextField) {
((JFormattedTextField) field).setValue(null);
}
if (field instanceof JTextComponent) {
((JTextComponent) field).setText(null);
}
}
}
#Override
public void keyReleased(KeyEvent ke) {
// do nothing
}
});
}