I’m trying to check the number button that has been pressed in an if statement. I’ve tried to google the question but perhaps I cannot phrase the question well enough.
Here is the code, I read that less code is easier to understand, so I’ve tried to condense my question as much as possible, I hope I haven't condensed it too much.
JButton One = new JButton("1");
One.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.append("1");
}
});
if(textArea.equals("1")){
System.out.println("test");//doesnt print
}
use a variable to store the text:
String theText;
theText = textArea.getText();
then do string comparison:
if(theText.equals("1")) {}
or shorthand:
if(textArea.getText().equals("1")) {}
Also, the if statement should be inside the actionPerformed method otherwise it has already been executed (resulting in FALSE) by the time the button is clicked. Use textArea.append() if you want to append a new "1" to each previous "1" in the text area every time the button is clicked, otherwise use textArea.setText() to just continually overwrite the previous "1" that was set from any previous button click. A working example can be seen here:
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JPanel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
public class Tester {
public static void main(String args[]) {
JButton aButton = new JButton("Button");
JPanel aPanel = new JPanel();
JTextArea aTextArea = new JTextArea();
JFrame aFrame = new JFrame();
aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
aFrame.setSize(200, 200);
aPanel.add(aTextArea);
aPanel.add(aButton);
aFrame.add(aPanel);
aFrame.setVisible(true);
aButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
aTextArea.setText("1");
if(aTextArea.getText().equals("1")) {
System.out.println("Test Works");
}
}});
}
}
UPDATE:
If you would like to not only check the contents of the text area when the button is pressed, but whenever text is entered. Kind of the same "idea" to your if-statement being outside of the button action listener. You need to use either a FocusListener or a KeyListener on the text area. A focus listener will execute when you either click in, or click out of the text area. A key listener will execute on various types of key press/release etc. I think what you are looking for is a KeyListener based on your comments. I've provided an example of each, that works with my previous example:
/*
This is probably not the one you want
*/
aTextArea.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
if(aTextArea.getText().equals("1")) {
System.out.println("Test Worls");
}
}});
/*
With this KeyListener
The second someone types "1" in the text area
It compares the strings, and the test works
*/
aTextArea.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
String currentText = aTextArea.getText();
if(currentText.equals("1")) {
JOptionPane.showMessageDialog(null, "Test Works");
}
}
public void keyPressed(KeyEvent e) {
}
});
Try inserting the above code in the example I had previously provided. Remember to comment out the button ActionListener and to import the following:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
Related
I wanted to make a KeyListener to stop the programm when I press the ESC key. But it only works when I did nothing else (pressed the button). I`m sorry if it is something super obvious but I cant find the mistake.
package basics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Graphic extends JFrame implements ActionListener, KeyListener {
private JButton button;
public Graphic() {
button = new JButton();
button.addActionListener(this);
button.setIcon(new ImageIcon("Image.jpg"));
this.getContentPane().add(button);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button){
//some code
}
}
public static void main(String[] args) {
JFrame bec = new Graphic();
bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
bec.setSize(1731, 563);
bec.setVisible(true);
bec.setTitle("title");
bec.requestFocus();
bec.addKeyListener(new Graphic());
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE){
System.exit(0);
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
KeyListener suffers from issues related to focusability and with other controls in the GUI. A simple solution would be to use the Actions API. Under this approach, the program simply specifies, for a given component, the “binding” or “mapping” between any key of interest and the Action (command) object to be invoked when that key is pressed (or released). Key bindings are associated with a specific GUI component.
In this case, a proper solution could be:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
public class Graphic extends JFrame implements ActionListener {
private JButton button;
public Graphic() {
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel"); //$NON-NLS-1$
getRootPane().getActionMap().put("Cancel", new AbstractAction(){ //$NON-NLS-1$
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
button = new JButton();
button.addActionListener(this);
button.setIcon(new ImageIcon("Image.jpg"));
this.getContentPane().add(button);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button){
//some code
}
}
public static void main(String[] args) {
JFrame bec = new Graphic();
bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
bec.setSize(1731, 563);
bec.setVisible(true);
bec.setTitle("title");
bec.requestFocus();
}
}
Are you sure there's no TextArea's or other focusable things? They can get focus, and key events will pass to them instead of listener.
UPD: Sorry, didn't see that you have nothing but button there.
You problem is to catch KeyListener across all components. You can do it like this:
public Graphic() {
// ...
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e -> {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose();
return true;
}
return false;
});
}
When you add this, your application will be closed exactly after you press ESC button. If you want to block it e.g. if some of you components have focus (e.g. JTextField and you want to do specific action), then you have to focus component in this listener and avoid invoking dispose().
But it only works when I did nothing else (pressed the button).
No it doesn't work (at all). Have a look at this code:
public static void main(String[] args) {
JFrame bec = new Graphic();
// ..
bec.addKeyListener(new Graphic());
}
The key listener is added to a 2nd instance of Graphic that is never displayed.
Another reason it would not work: Because a KeyListener (even when added to the correct instance) requires that the component to which it's added is both focusable (a JFrame by default is not) and has the input focus (which that frame will never have, given it is not focusable).
Solution: For Swing, we typically use key bindings rather than the lower level KeyListener. A key binging offers ways to specify on what conditions it will be invoked, some of which do not require the component to have focus.
I have a panel with a couple of text fields and an editable JComboBox used to perform a search. I want all of these to act as if I press the search button underneath when I press the enter key. This works fine for a JTextField with an ActionListener. However, I only want the JComboBox to start the search when enter is pressed and the drop down list isn't shown. I.e. if the user presses enter to select an option in the drop down nothing should happen.
How would I go about achieving this behaviour?
I tried checking getActionCommand() and it either shows "comboBoxEdited" or "comboBoxChanged" when the event is fired. "comboBoxEdited" is fired when enter is pressed after selecting an option as well as when pressing enter in the editable field. "comboBoxChanged" is fired when moving between options, as well as just before "comboBoxEdited" when enter is pressed after editing the text.
I tried an ugly hack where I store the previous ActionCommand, but it isn't perfect as the user will have to press enter twice after entering text manually.
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("comboBoxEdited") &&
!combohack.equals("comboBoxChanged")) {
combohack="";
//PERFORM SEARCH!
}
combohack=e.getActionCommand();
}
I furthermore tried to make my hack even uglier by adding a KeyListener as well to reset the string when actual letters where pressed, but that didn't help.
Any ideas?
Okay, this is a little heavy handed, but what this does is replaces the KeyEvent.VK_ENTER Action with our own Action
So basically, when the user presses the Enter key, our Action is notified, but the combo box is not (so the JComboBox won't trigger an ActionEvent for it - but will for selection changes)
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ComboBoxEditor;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
final JComboBox<String> cb = new JComboBox<>(new String[]{"Apples", "Bananas", "Pears"});
cb.setEditable(true);
SimpleComboBoxEditor editor = new SimpleComboBoxEditor();
InputMap im = editor.getInputMap();
ActionMap am = editor.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter");
am.put("enter", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if (!cb.isPopupVisible()) {
System.out.println("Editor did action");
}
cb.hidePopup();
}
});
cb.setEditor(editor);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Combobox did action");
}
});
add(cb);
}
public class SimpleComboBoxEditor extends JTextField implements ComboBoxEditor {
#Override
public Component getEditorComponent() {
return this;
}
#Override
public void setItem(Object anObject) {
if (anObject != null) {
setText(anObject.toString());
} else {
setText(null);
}
}
#Override
public Object getItem() {
return getText();
}
}
}
}
Thanks for the effort! It doesn't really work as I want it to though. It still fires the event with "comboBoxEdited" when [Enter] is pressed to choose the highlighted item instead of just closing the drop down leaving the chosen text in the editor. It should only fire the event when the drop down is closed and the user presses [Enter]. So [Enter] to choose an item, [Enter] again to fire the action.
So, I finally got to run the code on a Windows machine and basically, in the Action for the key binding, I made a check for isPopupVisible, when it's not, it will print the "editor did action" event, otherwise it does nothing
There is actually a rather simple and elegant solution:
combo.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_ENTER && !combo.isPopupVisible()) {
System.out.println("SEARCH!");
}
}
});
Note that the KeyListener won't work if added to the JComboBox directly, but has to be added to its EditorComponent.
I am trying to do a small app that compares two similar texts contained in 2 JTextarea. I am wondering if it's possible to select text from the first JTextarea and automatically select the text on the second JTeaxtarea (lets consider that it's guarantee that the 2 JTextarea will have the same text for now) ?
Should I share events or listeners ?
Thank you
This would be so much easier if JTextComponent supported a selection model...
Basically, what you can do is attach a ChangeListener to the JTextArea's Caret and monitor for changes to the Caret, changing the selection of the other JTextArea in response...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
public class MirrorTextSelection {
public static void main(String[] args) {
new MirrorTextSelection();
}
public MirrorTextSelection() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea left;
private JTextArea right;
private DefaultHighlighter.DefaultHighlightPainter highlightPainter;
public TestPane() {
highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(UIManager.getColor("TextArea.selectionBackground"));
left = new JTextArea(20, 20);
left.setWrapStyleWord(true);
left.setLineWrap(true);
right = new JTextArea(20, 20);
right.setWrapStyleWord(true);
right.setLineWrap(true);
left.setText("I am trying to do a small app that compares two similar texts contained in 2 JTextarea. I am wondering if it's possible to select text from the first JTextarea and automatically select the text on the second JTeaxtarea (lets consider that it's guarantee that the 2 JTextarea will have the same text for now) ? Should I share events or listeners ? Thank you");
right.setText("I am trying to do a small app that compares two similar texts contained in 2 JTextarea. I am wondering if it's possible to select text from the first JTextarea and automatically select the text on the second JTeaxtarea (lets consider that it's guarantee that the 2 JTextarea will have the same text for now) ? Should I share events or listeners ? Thank you");
setLayout(new GridLayout(0, 2));
add(new JScrollPane(left));
add(new JScrollPane(right));
left.getCaret().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int dot = left.getCaret().getDot();
int mark = left.getCaret().getMark();
right.setCaretPosition(mark);
right.moveCaretPosition(dot);
}
});
}
}
}
Now, when you run this, you will find that the right side doesn't seem to get highlighted...what?!
The selection is changing, it's just not been rendered because the component doesn't have focus...
Instead, you could use a Highlighter to highlight the text...
private DefaultHighlighter.DefaultHighlightPainter highlightPainter;
//...
highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(UIManager.getColor("TextArea.selectionBackground"));
left.getCaret().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int dot = left.getCaret().getDot();
int mark = left.getCaret().getMark();
right.getHighlighter().removeAllHighlights();
try {
int start = Math.min(dot, mark);
int end = Math.max(dot, mark);
right.getHighlighter().addHighlight(start, end, highlightPainter);
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
});
Okay, this is now working and you can control the background color of the highlight...
There is another alternative...We can replace the Caret of the right JTextArea with one that doesn't hide the selection when focus is lost...
public class HighlightCaret extends DefaultCaret {
#Override
public void install(JTextComponent c) {
super.install(c);
setSelectionVisible(true);
}
#Override
public void focusGained(FocusEvent e) {
JTextComponent component = getComponent();
if (component.isEnabled()) {
if (component.isEditable()) {
setVisible(true);
}
setSelectionVisible(true);
}
}
#Override
public void focusLost(FocusEvent e) {
setVisible(false);
}
}
Then we set the Caret to right...
right.setCaret(nwe HighlightCaret());
This means we don't need the Highlighter code, we can stick with the original and we get control over not only the background selection color but also the foreground selection color as well...
I have created buttons 1-9 as well as 4 text fields. I am trying to allow the user to click on any number 1-9 to input into each text field. However, I cannot determine which field the user is clicked on. Currently the 1-9 buttons only input text to the amt text field. How can I check which field is clicked and enter input into there?
New Question
public void actionPerformed(ActionEvent e) {
String iamt, ii, iterm,ipay;
iamt = amt.getText();
ii = interest.getText();
iterm = term.getText();
ipay = payment.getText();
Is there a way to shorten this if statement so I do not have redundant code for buttons 1-10?
if(e.getSource()==btn1) {
if(previouslyFocusedTextBox.equals(amt)){
amt.setText("1");
amt_number+=amt.getText();
amt.setText(amt_number);
}
else if (previouslyFocusedTextBox.equals(interest)){
interest.setText("1");
int_number+=interest.getText();
interest.setText(int_number);
}
else if (previouslyFocusedTextBox.equals(term)){
term.setText("1");
t_number+=term.getText();
term.setText(t_number);
}
else if (previouslyFocusedTextBox.equals(payment)){
payment.setText("1");
p_number+=payment.getText();
payment.setText(p_number);
}
}
if(e.getSource()==btnPay){
Loan = new LoanforCalc(Double.parseDouble(iamt),Double.parseDouble(ii),Integer.parseInt(iterm));
payment.setText(Double.toString(Loan.getPayment()));
}
I figured out what the OP meant, and made a quick solution:
Essentially, the textboxes lose focus as soon as the button is clicked, so we have to keep track of what had the focus before.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.FileNotFoundException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class FocusAwareWindow extends JFrame implements ActionListener, FocusListener {
public static void main(String[] args) throws FileNotFoundException {
FocusAwareWindow c = new FocusAwareWindow();
}
private JTextField textFieldA, textFieldB;
private JButton buttonA, buttonB;
private JTextField previouslyFocusedTextBox = textFieldA;
public FocusAwareWindow(){
super();
this.setLayout(new FlowLayout());
textFieldA = new JTextField();
textFieldA.setText("Field A");
textFieldA.setFocusable(true);
textFieldA.addFocusListener(this);
this.add(textFieldA);
textFieldB = new JTextField();
textFieldB.setText("Field B");
textFieldB.setFocusable(true);
textFieldB.addFocusListener(this);
this.add(textFieldB);
buttonA = new JButton("Which is focused?");
buttonA.addActionListener(this);
this.add(buttonA);
this.pack();
this.setVisible(true);;
}
public void actionPerformed(ActionEvent ev) {
if(previouslyFocusedTextBox.equals(textFieldA)){
System.out.println("Text Field A");
} else if(previouslyFocusedTextBox.equals(textFieldB)){
System.out.println("Text Field B");
}
}
public void focusGained(FocusEvent ev) {
if(ev.getSource() instanceof JTextField) {
previouslyFocusedTextBox = (JTextField) ev.getSource();
}
}
public void focusLost(FocusEvent ev) {
}
}
Maybe add a mouseListener and create areas over the textFields? Just guessing here but it might work. If this is possible then all you need is a variable to keep track of which area you clicked on and then check the variable for the textField you want.
I am working on a JTextPane that works (almost) exactly like the tags input field here on stackoverflow. For that I am converting text to components as soon as a user hits enter, tab or space. Naturally I do not want any of those characters to actually be input to the text pane. I found this solution, SSCCE:
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.StyledDocument;
#SuppressWarnings("serial")
public class TagTextPane extends JTextPane {
public TagTextPane() {
this.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "finalizeTag");
this.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "finalizeTag");
this.getInputMap().put(KeyStroke.getKeyStroke("TAB"), "focusNext");
this.getActionMap().put("focusNext", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
finalizeTag();
transferFocus();
}
});
this.getActionMap().put("finalizeTag", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
finalizeTag();
}
});
}
private void finalizeTag() {
StyledDocument doc = (StyledDocument) getDocument();
Element element = doc.getCharacterElement(getCaretPosition() - 1);
int start = element.getStartOffset();
int len = element.getEndOffset() - start;
String tag = "";
try {
tag = this.getDocument().getText(start, len);
} catch (BadLocationException e) {
}
this.setSelectionStart(start);
this.setSelectionEnd(start + len);
JLabel label = new JLabel(tag);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
this.insertComponent(label);
}
public static void main(String[] args) {
JFrame frame = new JFrame("TagTextPaneTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TagTextPane tPane = new TagTextPane();
frame.setSize(400, 100);
frame.getContentPane().add(tPane);
frame.setVisible(true);
}
}
Hitting "tab" usually causes a tab character to be inserted and hitting "enter" usually causes a line break to be entered, as well as hitting "space" causes a space to be entered. The weird thing is that my code stops line breaks and tabs from being entered, but still allows spaces to be entered normally, while performing the intended action.
Why does this approach behave differently for those keys?
How can I stop the space from being entered? (Maybe I want to extend this behavior to commas and the like later on.)
How can I optimally control the behavior of certain characters and keystrokes in a JTextComponent? I have seen this, where the suggestion is to use a KeyListener, but I have also seen this, where Rob Camick points out, why a KeyListener should not be used. So should I rather use a DocumentFilter, or is that breaking a butterfly on a wheel?
Is this even the best way to build this kind of tag input field?
this.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "finalizeTag");
This is handling the keyPressed event for the space character.
You want to handle the keyTyped event of the space character:
this.getInputMap().put(KeyStroke.getKeyStroke(' '), "finalizeTag");