I have a jframe of which I have made in Netbeans, this jframe is being "launched" by another java class, but for the current question that doesn't matter. What matters is the fact that I can't seem to figure out how to add my key listener to this jframe of mine. I have implemented the key listener, added the required functions (key typed, key pressed and key released). But I can't figure out how to actually add/initiate the actual key listener, to make it work.
As of right now I have tried two different things, first I have tried to add the line addKeylistener(new JFrameList()); in the start of the code, where the actual jframe is being initiated, but doing so the actual frame won't even show. Apart from this I have tried to add the same line within another function callJframFForm(), which is called from another class at the same time as the jframe is called. But this just returns the error non-static method addKeyListener(KeyListener) cannot be referenced from a static context. I am not sure what other ways I could add the key listener and thus am looking for a little help.
Currently my code looks like the one below.
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class JFrameList extends javax.swing.JFrame implements KeyListener{
public static String keyPresCod = "";
public JFrameList() {
initComponents();
addKeyListener(new JFrameList()); //This is where I am currently trying to call from, but frame won't show
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new JFrameList().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
// End of variables declaration
static void callJframFForm(){
try {
//This is where I have also tried to add the initialization line
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void keyTyped(KeyEvent e) {
int codeFKey = e.getKeyCode();
if (codeFKey == KeyEvent.VK_A) {
System.out.println("Button A clicked");
keyPresCod = "A";
} else if (codeFKey == KeyEvent.VK_B) {
System.out.println("Button B clicked");
keyPresCod = "B";
} else {
System.out.println("Different key pressed");
keyPresCod = "Another key";
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Problem
addKeyListener(new JFrameList())
This creates a new JFrameList object and uses it's listener. This means any keystrokes are being stored in the new object's member. To see the results, you would have to do
JFrameList list = new JFrameList();
addKeyListener(list);
//use list variable to access keyPressed code
Of course this isn't the behavior you want. You want the keys strokes to be stored in the current instance, not a new object. This means you should be doing
addKeyListener(this)
Although you may notice the listener only works "sometimes", or maybe not at all depending on how you're testing it.
Swing uses a focus system to manage which listeners should be receiving events, and since you are adding the listener to a JFrame, the listener will receive events only when the frame is in focus.
Solution
You should use key bindings rather than a key listener.
If you choose to continue using the listener, you should add it to your buttons, not your frame:
jButton1.addKeyListener(this);
jButton2.addKeyListener(this);
Instead of checking the key code of the event, you could grab the source of the event (your button) by calling event.getSource().
Key bindings allows you to set flexible focus settings for your components. All you need to do is access the input map of the component:
String actionCommand = "Press Button A";
jButton1.setActionCommand(actionCommand);
jButton1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), actionCommand);
jButton1.getActionMap(actionCommand, this);
Your JFrameList should now implement ActionListener rather than KeyListener, as it will be receiving your events as actions:
class JFrameList extends JFrame implements ActionListener {
private JButton jButton1;
public JFrameList() {
jButton1 = new JButton("A");
//set action command, add to input map, add to action map
}
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
System.out.println(button.getActionCommand() + " was performed.");
}
}
Alternative
JButton has built-in mnemonic handling. You can specify a mnemonic via JButton#setMnemonic(int), where the argument is a key code:
jButton1.setMnemonic(KeyEvent.VK_A);
This is the standard way of handling hotkeys in graphical interfaces. Simply hold down the Alt key (windows) then press the key you set the mnemonic to.
Key Events are only dispatched to the component with focus. You didn't post the entire code but I'm guessing that focus is on the button that you add to the frame, so the button gets the KeyEvent.
Not sure what you are trying to do with the KeyListener. You can't tell which button was clicked by looking at the character typed in the KeyEvent.
If you want to know what button is clicked then you need to add an ActionListener to each button. Read the section from the Swing tutorial on How to Use Buttons for more information and examples.
Related
I'm trying to create JPanel with two different buttons which one of them increasing and second decreasing size of text or window. I have class with button declaration. Everything is working when I put these buttons on JFrame separately.
I don't know how to get Action Listener in JPanel of each buttons. All I possibly do is listener of mouse click on JPanel...
Could you help me? I'm really begginer with coding so be polite please :]
public class ButtonMy extends Component {
private ButtonIncrease increase;
private PropertyChangeSupport propertyChangeSupport;
public ButtonMy() {
setPreferredSize(new Dimension(30,30));
kolor = Color.blue;
setForeground(kolor);
propertyChangeSupport = new PropertyChangeSupport(this);
increase = ButtonIncrease.Powieksz;
}
public ButtonIncrease getIncrease() {
return increase;
}
public void setIncrease(ButtonIncrease increase) {
ButtonIncrease oldIncrease = this.increase;
this.increase = increase;
propertyChangeSupport.firePropertyChange("increase", oldIncrease, increase);
}
public void addPropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.removePropertyChangeListener(l);
}
}
There is JPanel for bind 2 buttons. Here is the biggest problem :/ I'm lack of ideas.
public class ButtonB extends JPanel implements ActionListener{
public ButtonMy b1 = new ButtonMy();
public ButtonMy b2 = new ButtonMy();
public ButtonB (){
init();
}
public final void init(){
setLayout(new GridLayout(1,2));
this.przycisk1.setIncrease(ButtonIncrease.Powieksz);
this.przycisk2.setIncrease(ButtonIncrease.Zmniejsz);
add(b1);
add(b2);
}
}
JFrame where I test this component is very common. Code below shows only function for inc and dec size when separate button is clicked (not in JPanel).
private void buttonMy3MouseClicked(java.awt.event.MouseEvent evt) {
switch(buttonMy3.getIncrease()) {
case Powieksz: setSize(1);
break;
case Zmniejsz: setSize(0);
break;
}
}
I didn't paste full of my code. There some of math functions left which I think they are not needed here (setSize for example).
I'm not sure if i understand the problem correctly but I think under the actionListener class you should have a method called actionPerformed& it will say that if button1 is clicked increase the number, if button2 is clicked decrease the number:
public void actionPerformed( ActionEvent event ) {
if (event.getSource()== b1) // your "increase size" code
if(event.getSource()== b2)// your "decrease size" code
}
button listeners are actually different from mouse listeners; buttons implements ActionListeners and have the actionPerformed method with event variable. you could handle the event by:
getSource() -this method is inherited from java.util.EventObject and returns the OBJECT on which the event initially occurred (the button itself)
or by getActionCommand() -this method is available to action events, or any event that inherits from ActionEvent and returns the command STRING associated with this action.
however mouse listeners implements MouseListener and has a lot of methods depending on what the mouse does (pressed, clicked, released, etc.).
I added a JPanel to a JRadioButton - so that I may display whatever I want in the radio button.
This all worked as expected. But to allow for text wrapping, I used a JTextArea and added it to the JPanel contained within the radio button.
Now I have an issue where, if the user clicks on the JTextArea, then the JTextArea consumes the mouseEvent and as a result there is no response from the radio button (it doesn't 'select').
Is there a way get the JTextArea to ignore the mouse click, so that the parent may handle it instead?
I tried add the JTextArea's listeners to the radioButton instead.
I also tried to remove its listeners completely, but both these attempts failed.
Anyone have any suggestions?
Strong beware
Most JSomething are not meant to be used as containers even though it's possible - the outcome of doing it anyway is more or less visually and behaviourally undetermined!
That said, did it recently, to implement something similar to a Windows task dialog. If the requirement includes keeping the button clickable (and why else would you mis-use it as a container :-) the main problem (layout apart) is to make all added components completely mouse-transparent. Which is more difficult than can be expected. The minimum is to not allow adding of mouseListeners and disable the acceptance of mouseEvents:
final JTextArea area = new JTextArea("replacement ..") {
#Override
public synchronized void addMouseListener(MouseListener l) {
LOG.info("adding here ...?");
}
#Override
public synchronized void addMouseMotionListener(
MouseMotionListener l) {
}
#Override
public synchronized void addMouseWheelListener(
MouseWheelListener l) {
}
#Override
public void addNotify() {
disableEvents(AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK |
AWTEvent.MOUSE_WHEEL_EVENT_MASK);
super.addNotify();
}
};
Plus make sure it's not focusable
area.setEditable(false);
area.setFocusable(false);
area.setRequestFocusEnabled(false);
Plus unregister dragging and tooltips
ToolTipManager.sharedInstance().unregisterComponent(area);
area.setDragEnabled(false);
Nevertheless, there might still be surprises ahead, f.i. call the following twice (that is disable and enable again), which will internally re-enable mouseEvent:
area.setAutoscrolls(!area.getAutoscrolls());
So at the end of the day, we might get away with it - but never be entirely certain that we succeeded.
What about this? Create and add your own MouseListener to TextArea
JPanel p = new JPanel();
JTextArea t = new JTextArea("line \n line");
t.addMouseListener(new MyMouseListener());
p.add(t);
jRadioButton1.add(p);
jRadioButton1.addMouseListener(new MyRadioButtonMouseListener());
And in the MyMouseListener Dispatch event
private class MyMouseListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
Component source = (Component) e.getSource();
source.getParent().getParent().dispatchEvent(e); // 2x getParent() because JTextArea->JPanel->JRadio
}
.
.
.
}
And finally RadioButtonMouseListener
private class MyRadioButtonMouseListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("CLICK ON RADIOBUTTON !!");
}
.
.
.
}
I'm trying to code a telephone and the first thing I wanted to do is to assign a different sound to each button pressed.
I don't want to write ten handlers such as this one:
private void buttonOneHandler(java.awt.event.MouseEvent evt) {
try{
buttonSound = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.getAudioInputStream(new File("resources/buttonOne.wav"));
buttonSound.open(ais);
buttonSound.loop(0);
}
catch(Exception e)
{
e.printStackTrace();
}
}
Instead, I would like to use a unique handler, which accepts a String parameter (the route to the wav file), so that each button changes getAudioInputStream parameter value.
Is that possible?
Thank you very much.
private static class PlaySoundActionListener implements ActionListener {
private String soundPath;
private PlaySoundActionListener(String soundPath) {
this.soundPath = soundPath;
}
#Override
public void actionPerformed(ActionEvent e) {
// play the sound at this.soundPath
}
}
...
button1.addActionListener(new PlaySoundActionListener("resources/buttonOne.wav"));
button2.addActionListener(new PlaySoundActionListener("resources/buttonTwo.wav"));
button3.addActionListener(new PlaySoundActionListener("resources/buttonThree.wav"));
Note that a MouseListener is not the appropriate listener to use with a button. ActionListener is the one which is invoked when a button is clicked, and regardless of the way it's clicked (with the mouse, the keyboard, a keyboard shortcut).
This is possible by writing a single ActionListener, and registering it with each button.
You'd then have to use JButton(Action) constructor to force the button to generate your custom action on click.
This is covered in the swing tutorial:
http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html
I have a JButton that's attached to an ActionListener, but I also wanted to add a shortcut key to the button to be more user-friendly. Say, the user can click the button and the program performs some function "f" or the user can also press "Enter" on the keyboard to perform the same function f. So here's what the gist of my code looks like
private JButton button;
public static void main(String[] args){
Action buttonListener = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
//Perform function f
}
};
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ENTER"),
"test");
button.getActionMap().put("test",
buttonListener);
button.addActionListener(new OtherListener());
}
private class OtherListener implements ActionListener{
public void actionPerformed(ActionEvent e){
//Perform function f
}
}
Seems a bit tedious having to add an Action and an ActionListener to do the same thing. Maybe I'm not seeing it, but is there a way to cut the code down so I can eliminate the Action and just use the actionListener? I was thinking switching the buttonListener parameter in the getActionMap().put() method to but the method only takes Action types.
Action extends ActionListener, so you should be able to define a single Action and use it wherever you need an ActionListener.
e.g.
public static void main(String[] args){
Action buttonListener = new Action() {
public void actionPerformed(ActionEvent e) {
//Perform function f
}
};
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("ENTER"), "test");
button.getActionMap().put("test", buttonListener);
button.addActionListener(buttonListener);
}
JRootPane has a method setDefaultButton(...) that will do what you want. You will need to get the root pane from the top-level container, then you can call this method passing a reference to your JButton, and it will perform its action when enter is pressed on the GUI. And this makes sense when you think about it as "enter" is a special key, one whose behavior should be the responsibility of the GUI, not a single button.
I have the following bit of code in a method called by clicking the send button, or pressing enter in the message text field in a piece of code.
// In class ChatWindow
private void messageTextAreaKeyPressed(java.awt.event.KeyEvent evt) { // Event handler created by Netbeans GUI designer to call this method.
if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) {
sendMessage();
}
}
public void sendMessage() {
String currentMessage = messageTextArea.getText();
addMessage("You", currentMessage);
app.sendMessage(currentMessage, 1);
messageTextArea.setText("");
}
The last bit of code blanks the text area. However, after a message is sent by pressing the enter button, rather than being empty, the text box contains a newline.
My guess is that after my event handler runs, THEN the newline character is being added. How to I stop the newline being added?
try adding evt.consume() after your call to sendMessage()
private void messageTextAreaKeyPressed(java.awt.event.KeyEvent evt) {
if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) {
sendMessage();
evt.consume();
}
}
The default Action for the Enter key in a JTextArea is to insert a new line as you have seen. So the solution is to replace the default Action with a custom Action. The benefit of this approach is that this Action can also be used by the JButton (or JMenuItem etc.). An Action is basically the same as an ActionListener, all you need to do is implement the actionPerformed() method.
Read up on Key Bindings to see how this is done. All Swing components use Key Bindings.
as camickr said,
you should bind action to enter key;
Action sendAction = new AbstractAction("Send"){
public void actionPerformed(ActionEvent ae){
// do your stuff here
}
};
textarea.registerKeyboardAction(sendAction,
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
sendButton.setAction(sendAction);
if you are more interesed, I implemented Autoindent feature for textarea, using this technique:
here