How do I make a button press a key? - java

I'm wondering if its possible to make a button in JButton Press a key?
So for example If I have a button titled New Button, and I click it with the mouse. I want it to press my left arrow key.
Also is it possible to make it so that it keeps pressing it until I let go of the mouse? So more or less I click it and It presses my left arrow key continuously until I release the mouse then it stops?

I click it and It presses my left arrow key continuously until I release the mouse then it stops?
What is the point of this?
If you use the keyboard to press the left arrow, the KeyStroke is dispatched to the component that has focus. So if focus is on a text field, the left arrow will move the caret back one character.
If you click on a button, focus is now on the button and if you dispatch the left arrow to the button nothing will happen.
Maybe you are trying to use the left arrow key to do some kind of animation. If so, then you need to create an Action. Then you need to add code so that a button click or the pressing of the left arrow key can invoke this Action.
For the basic concepts of this approach you can read the Swing Tutorial. There are sections on:
How to Use Actions
How to Use Key Bindings
For a working example of this approach you can check out Motion Using the Keyboard. The MotionWithKeyBindings.java code does animation using the keyboard or the button.
Are you trying to do something like this? Here is a simple "Calculator" keyboard:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
// display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(50, 50) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
// UIManager.put("Button.margin", new Insets(10, 10, 10, 10) );
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
You click a button and the value is displayed in a text field.

Do this with the java.awt.Robot class. Do this like so:
//Creating a new robot:
Robot r = new Robot();
//Pressing a key (Put inside click handler method):
r.keyPress(KeyEvent.VK_LEFT /*VK_RIGHT, VK_TOP, and VK_BOTTOM are also acceptable.*/
//Releasing a key (Put inside release handler method):
r.keyRelease(KeyEvent.VK_LEFT /*VK_RIGHT, VK_TOP, and VK_BOTTOM are also acceptable.*/); //Release key
When doing this, you may want to hold the value of the key being pressed. Do this by defining a global variable with the KeyEvent.VK_* value, like so:
//In global space
public static /*Can be private, or protected.*/ int keyPressed = null;
//In click handler body:
keyPressed = KeyEvent.VK_LEFT /*VK_RIGHT, VK_TOP, and VK_BOTTOM are also acceptable.*/; //Set this to the value of the key you are pressing.
//In mouse release handler body:
r.keyRelease(keyPressed);

Related

Java application - Space vs Enter for activating buttons on Mac

I'm creating a java swing application. The window has several buttons, and I would like the user to use the tab key to switch between buttons, and then press enter to activate the selected button.
I've created a sample window below. It has two buttons and a label, and activating either button changes the text of the label.
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.UIManager;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ButtonTest
{
private JFrame frame;
// Create the application.
public ButtonTest() { initialize(); }
// Initialize the contents of the frame.
private void initialize()
{
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JLabel lblText = new JLabel("Text");
lblText.setBounds(167, 59, 46, 14);
frame.getContentPane().add(lblText);
JButton btnRed = new JButton("Red");
btnRed.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lblText.setText("Red");
}
});
btnRed.setBounds(74, 174, 89, 23);
frame.getContentPane().add(btnRed);
JButton btnBlue = new JButton("Blue");
btnBlue.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
lblText.setText("Blue");
}
});
btnBlue.setBounds(220, 174, 89, 23);
frame.getContentPane().add(btnBlue);
}
// Launch the application.
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
ButtonTest window = new ButtonTest();
window.frame.setVisible(true);
} catch (Exception e)
{
e.printStackTrace();
}
}
});
}
}
When I run this code, I can press tab to switch between buttons, and pressing space while one of the buttons is focused activates it. I would prefer to press enter instead of space to activate the focused button. I've seen other answers on this site that use the following line of code to fix this issue:
UIManager.put("Button.defaultButtonFollowsFocus", Boolean.TRUE);
This works on Windows, but it doesn't seem to work on Macs. On Macs, pressing space still works, and pressing enter still does nothing. Is there a solution that works on both platforms? (Note: to run this application on a Mac, I first export it to a runnable jar file.)
You can use Key Bindings to bind the existing Action to a different KeyStroke for a single button:
InputMap im = button.getInputMap();
im.put( KeyStroke.getKeyStroke( "ENTER" ), "pressed" );
im.put( KeyStroke.getKeyStroke( "released ENTER" ), "released" );
or for all buttons in your application.
InputMap im = (InputMap)UIManager.get("Button.focusInputMap");
im.put( KeyStroke.getKeyStroke( "ENTER" ), "pressed" );
im.put( KeyStroke.getKeyStroke( "released ENTER" ), "released" );
See: Enter Key and Button for more information.

How To Use JButton "If pressed and if released"

Im looking to use JButton in substitute of my Keylistener. Key listener has methods such as if pressed if released etc. Im looking to do the same thing with this JButton, Exp: If user clicks with mouse and holds mouse in clicked position code will execute until s/he releases the buttoning which execution of the code will cease.
What I tried? I tried to use JButton at first which didn't produce the result I wanted because form my understanding JButton requires a full "click" I have been playing with JToggleButton
if (JToggButton.getModel().isPressed()) which is still not working, can someone please point me in the right direction to produce the desired result?
SPECIFIC GOAL:
I want to use the a microphone method I built, I will click the Button that says Microphone and I will hold down the click until I'm ready to finish speaking into the Mic, think of Facebook how you hold down the mic with your thumb and when you release it the voice recording stops, so there would be 2 methods startLogic(); when pressed down and held and stopLogic(); when finally released when user is done speaking
Note that a simple but wrong solution is to use a MouseListener, wrong since this listener does not respond to button depression but rather mouse press, and this will miss button press if it is pressed by any means other than the mouse, such as the spacebar.
I would listen to the button's ButtonModel with a ChangeListener and respond to changes in its isPressed() state. This will work no matter what presses the button, be it the mouse or the spacebar. For example:
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class ButtonPressTest extends JPanel {
private JButton button = new JButton("Button");
private JTextArea textArea = new JTextArea(15, 15);
public ButtonPressTest() {
button.getModel().addChangeListener(new BtnModelListener());
textArea.setFocusable(false);
add(button);
add(new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
}
private class BtnModelListener implements ChangeListener {
private boolean pressed = false; // holds the last pressed state of the button
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
// if the current state differs from the previous state
if (model.isPressed() != pressed) {
String text = "Button pressed: " + model.isPressed() + "\n";
textArea.append(text);
pressed = model.isPressed();
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ButtonPressTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ButtonPressTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

How to attach key binding to up and down arrows of JSplitPane divider?

I have JSplitPane that has oneTouchExpandable set to true.
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitPane.setDividerSize(10);
splitPane.setOneTouchExpandable(true);
The problem is that I do not know how to attach key bindings to up and down arrows on JSplitPane's divider. For up arrow I want Ctrl+U and for down - Ctrl + D.
Thanks!
Implementation of the arrow button shown by OneTouchExpandable is UI label and will take extra work unnecessarily to bind them. You can easily use Key Binding on JSplitPane itself to control the JSplitPane divider location using setDividerLocation(int). Increase on Ctrl + U and Decrease on Ctrl + D. For example:
Action incrDividerLoc = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JSplitPane srcSplitPan = (JSplitPane) e.getSource();
(srcSplitPan).setDividerLocation(srcSplitPan.getDividerLocation()+10);
}
};
Action decrDividerLoc = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JSplitPane srcSplitPan = (JSplitPane) e.getSource();
(srcSplitPan).setDividerLocation(srcSplitPan.getDividerLocation()-10);
}
};
jSplitPane1.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK),
"increaseDivider");
jSplitPane1.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK),
"decreaseDivider");
jSplitPane1.getActionMap().put("increaseDivider", incrDividerLoc);
jSplitPane1.getActionMap().put("decreaseDivider", decrDividerLoc);
Note: method A value less than 0 passed to setDividerLocation(int) implies the divider should be reset to a value that attempts to honor the preferred size of the left/top component. After notifying the listeners, the last divider location is updated, via setLastDividerLocation.
The problem is that I do not know how to attach key bindings to up and down arrows on JSplitPane's divider.
Normally you would try to access the Action of the button. In many cases the component will already define an Action that you can use. See Key Bindings for a list of the default bindings for a JSplitPane. Unfortunately there is no Action to support the one touch clicking options.
So we need to access the buttons directly from the UI:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
public class SplitPaneDividerAction extends AbstractAction
{
private boolean leading;
public SplitPaneDividerAction(boolean leading)
{
this.leading = leading;
}
#Override
public void actionPerformed(ActionEvent e)
{
JSplitPane splitPane = (JSplitPane)e.getSource();
BasicSplitPaneUI ui = (BasicSplitPaneUI)splitPane.getUI();
BasicSplitPaneDivider divider = ui.getDivider();
if (leading)
((JButton)divider.getComponent(0)).doClick();
else
((JButton)divider.getComponent(1)).doClick();
}
private static void createAndShowUI()
{
JPanel leading = new JPanel();
leading.setPreferredSize( new Dimension(200, 100) );
leading.setBackground( Color.BLUE );
leading.setFocusable(true);
JPanel trailing = new JPanel();
trailing.setPreferredSize( new Dimension(200, 100) );
trailing.setBackground( Color.RED );
trailing.setFocusable(true);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leading, trailing);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(100);
InputMap im = splitPane.getInputMap(JSplitPane.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = splitPane.getActionMap();
im.put(KeyStroke.getKeyStroke("control U"), "leading");
im.put(KeyStroke.getKeyStroke("control D"), "trailing");
am.put("leading", new SplitPaneDividerAction(true));
am.put("trailing", new SplitPaneDividerAction(false));
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( splitPane );
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Of course this approach will only work if your LAF extends from the BasicSplitPaneUI.

How to show a tooltip on a mouse click

I have a JTreeTable and have successfully implemented a MouseMotionListener to show a tooltip whenever the mouse is over one of the cells. However when clicking on the cell the tooltip does not show up. I've tried several things like setting the text on the mouseClicked and mouseReleased events but that doesn't work. I found this code -
Action toolTipAction = treeTable.getActionMap().get("postTip");
if(toolTipAction != null){
ActionEvent postTip = new ActionEvent(treeTable,ActionEvent.ACTION_PERFORMED, "");
toolTipAction.actionPerformed(postTip);
}
to use in the mouseReleased method, which does make the tooltip popup, but it's then in the wrong position. So next i tried overriding the getTooltipLocation method on the JTreeTable, and this works fine for mouseMoved events but doesn't get called with the above method. Can anyone shed some light on how to do this?
Thanks
Andy
You can use the following approach to show the tooltip (there will be a slight delay). Then you can override the getToolTipLocation() method since a MouseEvent will now be generated:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToolTipOnRelease extends JPanel
{
public ToolTipOnRelease()
{
JLabel label = new JLabel( "First Name:" );
add( label );
JTextField textField = new JTextField(15);
add( textField );
MouseListener ml = new MouseAdapter()
{
public void mouseReleased(MouseEvent e)
{
JComponent component = (JComponent)e.getSource();
component.setToolTipText("Mouse released on: " + component.getClass().toString());
MouseEvent phantom = new MouseEvent(
component,
MouseEvent.MOUSE_MOVED,
System.currentTimeMillis(),
0,
0,
0,
0,
false);
ToolTipManager.sharedInstance().mouseMoved(phantom);
}
};
label.addMouseListener( ml );
textField.addMouseListener( ml );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("ToolTipOnRelease");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new ToolTipOnRelease() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
org.apache.jorphan.gui.JTreeTable extends javax.swing.JComponent
javax.swing.JComponent#setToopTipText() doesn't work?
I do realize that you want to use Action but for tooltips? I would use Action when multiple UI actions would need to share it.

Java KeyEvents for a KeyPad component

I'm writing a Java application that will have an on-screen number pad available for touch-input. Normal key input will also be available, but I'd like the keypad there for tablets and such. I've made a class that extends JPanel. It has 10 buttons laid out in the normal keypad configuration. Now I'm trying to figure out how to make it act like a regular keypad.
I just don't know how to issue KeyEvents. Here's what I've tried so far:
I tried adding a new KeyListener. In the JPanel, when a button was pressed, the action listener called a method that created a new KeyEvent and sent it to all the KeyListeners that were added to the JPanel. However, no matter how many times I added KeyListeners, the didn't seem to be any associated with the panel.
Another thing I tried was passing the target JTextField to the JPanel and setting a member object to the JTextField. But every time I try to append text to it, the member object is null. It's really perplexing to me.
I'm hoping someone could point me in the correct direction with how to implement this keypad to make it as modular is possible so it can be used inside several different screens.
Thanks in advance!
Brent
You dont need the KeyListener you can associate yourself the outcome effect of pressing a button (its not a key) on the JTextField.
Maybe something like:
New JButton button = new JButton(new KeyPressedAction(mTextField,"0"));
Where
public class KeyPressedAction extends Action{
JTextField tf;
String num;
public KeyPressedAction(JTextField textField,String num){
this.tf = textField;
this.num = num;
}
public void actionPerformed(ActionEvent e){
textField.setText(textField.getText+num);
}
}
I'm writing a Java application that
will have an on-screen number pad
available for touch-input.
So I assume that when the button is "touched" an ActionEvent will be generated. Then I assume you will want to add the character related to the button to a text field. If so, then the following examples should get you started. You don't need to generated KeyEvents, you just respond to the ActionEvents:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonCalculator extends JFrame implements ActionListener
{
private JButton[] buttons;
private JTextField display;
public ButtonCalculator()
{
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
buttons = new JButton[10];
for (int i = 0; i < buttons.length; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( this );
button.setMnemonic( text.charAt(0) );
buttons[i] = button;
buttonPanel.add( button );
}
getContentPane().add(display, BorderLayout.NORTH);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setResizable( false );
}
public void actionPerformed(ActionEvent e)
{
JButton source = (JButton)e.getSource();
display.replaceSelection( source.getActionCommand() );
}
public static void main(String[] args)
{
ButtonCalculator frame = new ButtonCalculator();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
If that doesn't solve your problem, then you should be looking into Key Bindings instead of using KeyEvents.

Categories

Resources