I have tried multiple times to find out a solution on my own by consulting Google, but this question, as ridiculously easy as it seems, has no documented answer. It seems to me.
All I want to know is: How to call a method from a keystroke?
Example: Pressing ctrl + up -> call method zoomUp();
ps: would be nice if that keystroke could be bound to a JTextPane.
Update
Until now my solution was to:
Create an Item: JMenuItem up = new JMenuItem("up");
Create a shortcut:
up.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_UP,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Catch the event by a listener:
up.addActionListener(new java.awt.event.ActionListener() { public
void actionPerformed(ActionEvent event) {
//Do stuff } });
(- never add the Item so it is a hidden shortcut)
But this is obviously ridiculous.
You cannot use JMenuItem to create "hidden" short cuts. The short cuts of JMenuItems become active once the JMenuItem gets indirectly added to a Window (usually via <-JMenu<-JMenuBar<-JFrame). Without that link, it cannot be known whether or not the accelerator is to be triggered or not, as the same accelerator might trigger different actions in different application windows.
You need to use a KeyListener on the component or frame in which you want to react.
Related
I've written a basic calculator type program using WindowsBuilder in Eclise neon and Java 1.8. It's pretty much complete, with everything working how I want it to. Except keyboard entry.
As a finishing touch I'd like to detect keyTyped events and map them to button presses so users can use the keyboard for entry instead of clicking buttons with the mouse.
I've added 'implements KeyListener' to the program class...
public class CashRegister implements KeyListener {
private JTextField keyb;
I've tried to set a listener to a invisible JTextField called keyb....
private void initialize() {
keyb = new JTextField(20);
keyb.addKeyListener(this);
keyb.setFocusable(true);
keyb.requestFocusInWindow();
And I've added methods to handle the captured keypress...
public void keyTyped (KeyEvent e) {
String out = "";
out = out + e.getKeyChar();
pence1text.setText(out);
}
public void keyPressed (KeyEvent e) {
}
public void keyReleased (KeyEvent e) {
}
So, at this stage all I'm expecting, prove it is working, is the keycharacter I press to appear in the textfield called 'pence1text'. However, it doesn't work, when I press the a key nothing is displayed.
I think it could be a focus problem. Googling around and checking stackoverlow lead me to add the following lines...
keyb.setFocusable(true);
keyb.requestFocusInWindow();
as above, but still no luck.
Does anyone have any ideas what I am doing wrong, or what I can try next?
Thanks
Thanks to user Andrew Thompson for pointing me back to the docs and a re-read.
The problem is that the JTextField is not visable and thus can't be given focus. If I add the listener to a textfield that is visable then the program works correctly. However if the user uses the mouse to click a button it loses focus and breaks the implementation...so I need to rethink the code and keep looking at focuse settings.
As a finishing touch I'd like to detect keyTyped events and map them to button presses so users can use the keyboard for entry instead of clicking buttons with the mouse.
Don't use a KeyListener.
Instead you should be using Key Bindings. Read the section from the Swing tutorial on How to Use Key Bindings for basic information.
Also check out: how to put actionlistenerand actioncommand to multiple jbuttons for a working example that shows how you can apply the key bindings to a calculator.
So far I've got ESC key to close the window, using the following code:
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action escapeAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
screen.dispose();
}
};
screen.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
screen.getRootPane().getActionMap().put("ESCAPE", escapeAction);
But I am wondering how I would go about adding a CTRL+A event? I remember reading about a way where you set booleans for keypressed/released, but I don't see that working with this piece of code, so I am wondering how I can implement CTRL+A.
Thank You
It's the second parameter of the KeyStroke.getKeyStroke(...) method that matters, as you'll want to use the InputEvent.CTRL_DOWN_MASK there to let the KeyEvent.VK_A be a control-A.
e.g.,
KeyStroke ctrlAKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A,
InputEvent.CTRL_DOWN_MASK);
I wouldn't worry about using the 3 parameter method that uses a boolean since you're more interested in key press, not key down or key release.
Regarding your comment:
Correction to my earlier comment. It works, if I make it let's say Ctrl+W. Ctrl+A just attempts to do its native "select all" function in a textfield in the frame. Any way to avoid that?
From the little I understand, this will be a problem if the component that has focus (such as a JTextArea) responds directly to the ctrl-A key press. To get around this, you can add the same binding to this component, but being sure to bind it to its InputMap that uses the JComponent.WHEN_FOCUSED; condition.
I am new to Java and am in the process of making a GUI of CLI application of Poker Game. It requires "Enter Key" to continue. I have tried to find out if there is some Event Handler for "Enter Key" so that I could change that Event to Mouse Button. But unfortunately I could not find any such thing. Now I have thought of passing carriage return to Java Console onClick Event. I have tried:
ContinueBtn = new JButton();
ContinueBtn.addMouseListener(this);
.
.
.
public void mouseReleased(MouseEvent e) {
System.out.println("\r\n");
//OR
char c = (char) KeyEvent.VK_ENTER;
System.out.println(c)
//OR
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
out.write("\r\n");
out.newLine();
out.flush();
//OR
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
out.write((char)10); /*OR*/ out.write((char)13);
}
It is still not working. Can anyone suggest what should I do?
Add proper Action or ActionListener, then implements KeyBindings, output form
KeyBindings should be javax.swing.Action, inside this Action call
myButton.doClick()
that invoke Action or ActionListener added to the JButton
For 'Enter' on JButtons, you probably want to use JRootPane.setDefaultButton(). Both JWindow and JDialog have a getRootPane() method.
The only trick is that the window / dialog has to be visible already to set the default button. I usually just override setVisible() in the windows that need a default button:
public void setVisible(boolean b) {
if (b) {
getRootPane().setDefaultButton(button);
}
super.setVisible(b);
}
I am not clear about your question, but from what i understand about your situation this might help.
(anything like a button)ActionPerformed(java.awt.event.ActionEvent evt)
Key bindings in Swing are handled with InputMaps and ActionMaps.
Sun has a nice tutorial on the key binding API. The tutorial has this to say:
An alternative to key bindings is using key listeners. Key listeners
have their place as a low-level interface to keyboard input, but for
responding to individual keys key bindings are more appropriate and
tend to result in more easily maintained code. Key listeners are also
difficult if the key binding is to be active when the component
doesn't have focus. Some of the advantages of key bindings are they're
somewhat self documenting, take the containment hierarchy into
account, encourage reusable chunks of code (Action objects), and allow
actions to be easily removed, customized, or shared. Also, they make
it easy to change the key to which an action is bound. Another
advantage of Actions is that they have an enabled state which provides
an easy way to disable the action without having to track which
component it is attached to.
java.awt.event.KeyListener (KeyListener Tutorial).
OK, so if I add an ActionListener to a GUI element, and it's the only element I use that ActionListener with, does it matter which of the following lines (a,b) I use to get the checkbox selected state?
final JCheckBox checkbox = (JCheckBox)this.buildResult.get("cbDebugTick");
checkbox.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent event){
boolean bChecked =
// (a) checkbox.isSelected();
// (b) ((JCheckBox)event.getSource()).isSelected();
model.setPrintDebugOn(bChecked);
}
});
It makes sense to me that if I add the ActionListener object to multiple GUI elements, then I should use (b).
And in (b), is it OK to blindly cast event.getSource() to JCheckBox, since I'm the one who added the action listener, or should I program defensively and do an instanceof check?
note: this question is in the context of event listeners in general; kdgregory has some good points below specifically re: checkboxes which I had neglected to consider.
I'd do neither.
If clicking the checkbox is going to start some action, I'd attach an ItemListener, then just look at the selection state in the ItemEvent.
However, checkboxes don't normally invoke actions, they manage state. So a better approach is to examine all of your checkboxes in response to whatever does kick off the action.
Edit: some commentary about the larger issues that the OP raised.
First, it's important to realize that large parts of Swing represent implementation convenience rather than a coherent behavior model. JCheckBox and JButton have nothing in common other than the fact that clicking within their space is meaningful. However, they both inherit from AbstractButton, which provides implementation details such as the button's label. It also assumes that buttons are "pressed", and that pressing a button will initiate some meaningful behavior (the action). In the case of JCheckbox, however, the button press is not important, the change in state is. That state change is signaled to the ItemListener -- which is also defined on AbstractButton even though state changes are meaningless to other button types (the JavaDoc even says "checkbox").
One of the things that Swing did get right -- if hard to use -- is the idea of that an Action is separate from the control initiating that action. An Action object can be invoked from multiple controls: a menu item, a pushbutton on a dialog, a keystroke, whatever. More important from a design perspective is that it takes you away from the idea of a generic "listener" that tries to figure out what needs to happen. I've seen apps where a single listener receives input from the entire menu system, for example, and then runs through a big if/else chain to figure out which menu item was pressed. Using Actions means you have more classes, but in the long run gives you a more maintainable app.
Finally, from a usability perspective, there's a difference between controls that maintain state, such as JCheckbox and JTextArea, and those that initiate actions, such as JButton and JMenuItem. I have seen a (web) app where clicking on a radio button takes you to a different page. That's bad. Even if you're planning to use listeners internally, to update the state of some model, you should ask yourself why the collection of GUI elements do not in themselves provide you with a model.
For the case where the listener is exclusive (such as an anon listener), I use (a).
If the listener will be reused (eg, this is an instance of ActionListener) I'll write it as:
#Override
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
if (src == checkbox) {
boolean bChecked = checkbox.isSelected();
// ...
}
}
If you have several checkboxes and they are processed the same way, then instanceof makes sense.
in (b) to be rigourous, you should indeed do a instanceof check, but it's not that important. I would think both these lines are fine and acceptable, though (b) would be "better code"
Although, what is usually done in an action listener is simply call another method customized to your checkbox. So it would look like something like this:
#Override public void actionPerformed(ActionEvent event) {
//your treatment would be in this method, where it would be acceptable to use (a)
onCheckBoxActionPerformed(event)
}
I'd program with b defensively as it's the best-practice option. But if only you are ever going to use the code then there is no reason why you can't do a. However, imagine how happy you will be with yourself if you come back to it at some future point, change something and find you wrote good code which you can directly reuse...
Bit of a strange one.
I want to have a JTextField, in which the user will type a string. While typing, however, I'd like that text to automatically print to another JTextField in real time.
I'm not sure if this is possible because I can't recall seeing any application do it.
Anyone even seen anything like this before?
Actually, now that I open my eyes a bit, I see that stackoverflow does it.
Are there any known ways of implementing in Java?
You might be able to give the fields the same document instance. For the document you could use one of the classes that swing provides or you could extend your own. The document is the model of the text field.
Alternatively you could use listeners to do the updating. There are many things you can listen and it depends on your needs what suits best. You can listen the document, you can listen keyboard and mouse events, you can listen for action events. (Action events happen in this kind of fields when pressing enter or focus is lost.)
The "same document" approach is the way to go.
Here's some sample code in Groovy (translation to Java is left as an exercise to the reader):
import javax.swing.*
import java.awt.FlowLayout
f = new JFrame("foo")
t1 = new JTextField(10)
t2 = new JTextField(10)
t2.document = t1.document
f.contentPane.layout=new FlowLayout()
f.contentPane.add(t1)
f.contentPane.add(t2)
f.pack()
f.show()
Add an ActionListener, as this will respond for any action changing the text (not just key presses, but also mouse-driven cut-paste). Code not tested...
// changing textField1 updates textField2
textField1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
textField2.setText(textField1.getText());
}
});
You could add an action listener for the jTextField's key released action.
eg:
jTextField1.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(java.awt.event.KeyEvent evt)
{
jTextField1KeyReleased(evt);
}
});
private void jTextField1KeyReleased(java.awt.event.KeyEvent evt)
{
jTextField2.setText(jTextField1.getText());
}
You could use the KeyListener interface, and on each keyTyped event you copy the text to the "duplicate" field.