Well what i'm trying to do is change the text of the JRadioButton's when they're selected, i got them to change the color. I know I can do it by putting the code to change the text inside the dedicated event handling method specific to each button, but how do I do it so that I use A DIFFERENT event handling method that just changes the buttons? I already created one but it doesn't work, here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LessonTwenty extends JFrame implements ActionListener{
JRadioButton b1,b2;
JTextArea t1;
JScrollPane s1;
JPanel jp = new JPanel();
public LessonTwenty()
{
b1= new JRadioButton("green");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jp.setBackground(Color.GREEN);
}
});
b2= new JRadioButton("red");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jp.setBackground(Color.RED);
}
});
//Method to change the text of the JRadion Buttons, what i'm trying to make work
new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(b1.isSelected()){
b1.setText("Welcome");
}
else if(b2.isSelected()){
b2.setText("Hello");
}
}
};
jp.add(b1);
jp.add(b2);
this.add(jp);
setTitle("Card");
setSize(700,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String [ ] args){
new LessonTwenty();
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
if i understand you right, you want do do something like this:
//Method to change the text of the JRadion Buttons, what i'm trying to make work
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(b1.isSelected()){
b1.setText("Welcome");
}
else if(b2.isSelected()){
b2.setText("Hello");
}
}
};
b1= new JRadioButton("green");
b1.addActionListener(al);
b2= new JRadioButton("red");
b2.addActionListener(al);
ie. you define one ActionListener which you use in all your objects.
The anonymous object you define in your original code does absolutely nothing, it just creates an ActionListener which nobody can ever access, since it is not assigned to any Button.
Maybe this could help
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(e.getSource() == b1){
b1.setText("Welcome");
} else if(e.getSource() == b2){
b2.setText("Hello");
}
}
};
Related
Like I described in the title, I am required to make a JButton clicked if a key from a keyboard is pressed. For example :
ActionListenerClass actionListener = new ActionListenerClass();
KeyListenerClass actionListener = new KeyListenerClass();
JButton aButton = new JButton("A");
aButton.setActionCommand("A");
aButton.addActionListener(actionListener);
aButton.addKeyListener(keyListener);
When "A" is pressed from the keyboard, button A will perform a doClick() and send the action command to a private class of the action listener for event handling. Now I have read a lot of solution from stack overflow, and they all used key binding, which is to bind between an input map and an action map. The thing is I absolutely have to use a key listener with a private class but not the binding. The only thing I can guess now is the keyListener above have to somehow receive the keyboard input and perform doClick on the button it is binded to in a keyPressed method, which I have try and it didn't work at all.
Edit: Here's my entire code.
CalculatorViewController.java
import java.awt.*;
import java.awt.event.*;
import java.util.regex.Pattern;
import javax.swing.*;
/**Create the app GUI
* #author Bach Le
* #version 1.0
* #see java.awt, java.awt.event, javax.swing
* #since 12.0.1
*/
public class CalculatorViewController extends JPanel {
private JButton backSpaceButton;
public CalculatorViewController() {
Controller controller = new Controller();
KeyController keyController = new KeyController();
setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5,Color.black));//Adding the panel border
backSpaceButton = new JButton("\u21DA");
backSpaceButton.setPreferredSize(new Dimension(52,55));
backSpaceButton.setOpaque(false);//set transparency
backSpaceButton.setContentAreaFilled(false);
backSpaceButton.setBorderPainted(false);
backSpaceButton.setActionCommand("Backspace Button");//set the action command
backSpaceButton.addActionListener(controller);//add action listener
backSpaceButton.setToolTipText("Backspace (Alt+B)");//set tooltip text
backSpaceButton.setFont(font);//set the font
backSpaceButton.addKeyListener(keyController);
add(backSpaceButton) ;
}
private class Controller implements ActionListener{
public void actionPerformed(ActionEvent e) {
//event handling here
}
}
private class KeyController implements KeyListener{
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==65) {
backSpaceButton.doClick();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
}
2.Calculator.java
public class Calculator {
public static void main(String[] args) {
CalculatorViewController pane = new CalculatorViewController();
JFrame frame = new JFrame("Calculator");
frame.setContentPane(pane);
frame.setSize(380, 520);
frame.setLocationByPlatform(true);
frame.setResizable(true);
frame.setVisible(true);
}
}
Focus on CalculatorViewController, I am trying to make backSpaceButton clicked when A is pressed (Of course it is the actual backspace button but I will fix it later), so it will send its action command to the action listener registered to it, which will be processed in the method of Controller inner class. I am not sure the proper way to achieve this.
Adding a KeyListener will only work for components with focus. You would not want to add the KeyListener to the JButtons, because only one JButton will be in focus.
For just setting a value you could use setMnemonic but then you would have to use a modifier (such as 'alt) when you press the key.
The 'correct' way to do this is to use key bindings
Here is an example with two buttons.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonKeys{
public void buildGui(){
JFrame frame = new JFrame("key buttons");
JPanel panel = new JPanel(new BorderLayout());
JButton a = new JButton("A");
a.addActionListener(evt->{ System.out.println("a pressed");});
JButton b = new JButton("B");
b.addActionListener(evt->{ System.out.println("b pressed");});
panel.add(a, BorderLayout.EAST);
panel.add(b, BorderLayout.WEST);
frame.setContentPane(panel);
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false);
panel.getInputMap().put(us, "A");
panel.getActionMap().put("A", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
a.doClick();
}
});
KeyStroke us2 = KeyStroke.getKeyStroke(KeyEvent.VK_B, 0, false);
panel.getInputMap().put(us2, "B");
panel.getActionMap().put("B", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
b.doClick();
}
});
a.setFocusable(false);
b.setFocusable(false);
}
public static void main(String[] args){
EventQueue.invokeLater( new ButtonKeys()::buildGui);
}
}
I made the buttons to not obtain focus because if they get focus then their input map will be used.
This code should work for you. For the KeyListener I used a KeyAdapter more here as it is more convenient if you simply need to use one of the methods. You can of course move the Listeners to separate own classes if needed, but the behavior would stay the same.
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton btn = new JButton("A");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked");
}
});
btn.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == 'A' || e.getKeyChar() == 'a') {
((JButton) e.getSource()).doClick();
}
}
});
panel.add(btn);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 800, 600);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
If you really need to use a KeyListener, it would look like this:
btn.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == 'A' || e.getKeyChar() == 'a') {
((JButton) e.getSource()).doClick();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
});
This is my first question and I'm realy sorry for my English. I don't want to navigation in JComboBox's dropdown list show the selected item in the "JComboBox's main field" (sorry, don't know how to call it, see the images).
This is what happen when I navigate in list:
But I want something like this:
and when I press Enter or clicked on item, it appear in the main field.
Here is my code:
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.*;
public class ComboTest {
JFrame frame;
JPanel panel;
String[] choices = new String[]{
"Java",
"Python",
"C++",
"PHP",
"Perl"
};
JComboBox<String> comboBox = new JComboBox<>(choices);
JTextComponent textComponent;
public static void main(String[] args){
new ComboTest();
}
public ComboTest() {
frame = new JFrame();
panel = new JPanel();
textComponent = (JTextComponent) comboBox.getEditor().getEditorComponent();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 150);
frame.setResizable(false);
panel.setLayout(new FlowLayout());
comboBox.setEditable(true);
comboBox.setSelectedItem(null);
panel.add(comboBox);
frame.add(panel);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Try this code block
comboBox.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
//when Popupmenu is visible, remove the combobox editor text
comboBox.getEditor().setItem(null);
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
Thanks to zilk. Your answer helped me to solve this. The listener addPopupMenuListener doesn't work for me. But when I changed the addPopupMenuListener to addItemListener, everything worked fine.
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(final ItemEvent itemEvent) {
comboBox.getEditor().setItem(null);
comboBox.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
comboBox.getEditor().setItem(itemEvent.getItem());
}
}
});
}
});
Ok. I'm not sure about the title of my question and whether I used the right words.
As I am a self taught total amateur I'm finding it hard to ask my question as I don't know the correct terms for things so I will write something in code and then ask my question. I've written it without import statements, setting up layouts and scrollbars and some other things just to keep it simpler.
public class Foo{
JTextArea text;
public static void main(String[] args){
Foo foo = new Foo;
foo.go();
}
public void go(){
JFrame frame = new JFrame();
JButton button = new JButton("One");
JButton button2 = new JButton("Two");
JPanel panel = new JPanel();
frame.setVisible(true);
frame.setSize(600, 300);
frame.getContentPane().add(BorderLayout.EAST, panel);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(button);
panel.add(button2);
text = new JTextArea(10, 20);
panel.add(text);
button.addActionListener(new ButtLis());
button2.addActionListener(new ButtLis());
}
class ButtLis implements ActionListener{
#override
// this is where I have the problem
text.append();
}
}
What I want is an if statement to go into my inner class (ButtLis) which will determine which of the buttons are pressed and then append certain text to the JTextArea based on that. But I don't know what to call to find out which button was pressed.
You have a couple options. In the current case you have, where the JButton objects are locally scoped within the constructor, you would need to check for actionCommmand because the objects are not accessible from the ActionListener with their current scope. So you could do this
class ButtLis implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if ("One".equals(command)) {
// do something
}
}
}
If you wanted to compare object source, you would need to give your buttons a global scope
public class Foo {
JButton button = new JButton("One");
JButton button2 = new JButton("Two");
class ButtLis implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
}
}
}
}
A third option is to register the buttons individually
public void go() {
...
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
}
See more at How to use Common Button and How to Write ActionListeners
I think this is what you're looking for, although I would hardly recommend it:
class ButtLis implements ActionListener {
private JTextArea text;
public ButtLis(JTextArea text) {
this.text = text;
}
#Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton)e.getSource(); // Warning! This is not good coding practice, because you don't know that the source will be a button
text.append(button.getText());
}
}
Instead, I'd recommend:
JButton button1 = new JButton("One");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
text.append("one");
}
});
That uses an "anonymous inner class" to define the action listener. For Button2, you'd say a similar thing. The benefits here are that the action listener is right next to the button that it works on, and it prevents you from having a single ActionListener that has to check where each event came from (using e.getSource()).
Inside your ButtLis, add this
class ButtLis implements ActionListener {
public void actionPerformed(ActionEvent e) {
e.getSource();
//Your implementation
}
}
Here the class that implements ActionListener:
class ButtLis implements ActionListener {
JTextArea text;
public ButtLis(JTextArea text) {
this.text = text;
}
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() instanceof JButton) {
JButton button = (JButton) ae.getSource();
if(text != null){
text.append(" " + button.getText());
}
}
}
}
And here how to add an action listener to the buttons:
button.addActionListener(new ButtLis(text));
button2.addActionListener(new ButtLis(text));
For a generale ActionListsner, i suggest a different customer ActionListener like this:
abstract class ButtLis implements ActionListener {
protected String sourceEvent; //or you can use a reference for the source object
public ButtLis(String sourceEvent) {
this.sourceEvent = sourceEvent;
}
public String getSourceEvent() {
return sourceEvent;
}
#Override
public void actionPerformed(ActionEvent ae) {
customer_actionPerformed(ae);
}
public abstract void customer_actionPerformed(ActionEvent ae);
}
And the adding of action listener for any component is the same as an ordinary ActionListener:
//for exemple button
button.addActionListener(new ButtLis(button.getText()) {
#Override
public void customer_actionPerformed(ActionEvent ae) {
text.append(getSourceEvent());
}
});
I have JButton and want on event call this class method show() when this button in pressed. I know how to this, if I want use method from another class, but I need call method from same class as button.
JButton search = new JButton(new ButtonAction("Search", KeyEvent.VK_A));
I try add
JButton search = new JButton(show());
But it works only 1 time when object creating, but not when button is pressed.
Not sure what you want here... but if you want to attach an actionListener() to a JButton, you can do the following. Why do you need to listen to A?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionListenerExample1 extends JFrame
implements ActionListener, KeyListener {
private static final long serialVersionUID = 1L;
private JTextField searchText;
private JButton searchButton1;
private JButton searchButton2;
public ActionListenerExample1() {
initialize();
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
protected void initialize() {
searchText = new JTextField(30);
searchButton1 = new JButton("Search 1");
searchButton2 = new JButton("Search 2");
searchText.addKeyListener(this);
searchButton1.addActionListener(this);
searchButton2.addActionListener(new ButtonAction());
this.setLayout(new FlowLayout());
this.add(searchText);
this.add(searchButton1);
this.add(searchButton2);
}
public static void main(String[] args) {
new ActionListenerExample1();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == searchButton1) {
buttonAction("GLOBAL LISTENER");
}
}
private class ButtonAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
buttonAction("LOCAL LISTENER");
}
}
private void buttonAction(String label) {
JOptionPane.showMessageDialog(this,
String.format("%s: %s", label, searchText.getText()));
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_A) {
buttonAction("KEYBOARD");
}
}
#Override
public void keyReleased(KeyEvent e) { }
#Override
public void keyTyped(KeyEvent e) { }
}
If I understand you correctly, you want to call a method from the class that you created the button in rather than a method from another class.
First off, notice that while you are technically calling a method here
JButton search = new JButton(new ButtonAction("Search", KeyEvent.VK_A));
what is really going on is that you are passing a ButtonAction object to the JButton constructor. The closest thing that I can think of that will get what you want is having the class you are using extend ButtonAction.
I have a problem with the focus listener implemented by CustomTextField class. The focus listener is only called when another Swing component is getting the focus. But If I move the JFrame istelf by dragging it with the mouse, the focusLost() method is never called (in other words, it doesn´t seem that the focus is shifting from CustomTextField to JFrame).
EDIT: The solution of my question is below:
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.*;
public class ScrollFocus extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollFocus();
}
});
}
public ScrollFocus() {
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Vector<String> values = new Vector<>();
values.add("a");
values.add("b");
values.add("c");
values.add("d");
values.add("e");
JComboBox<String> comboBox = new JComboBox<>(values);
JScrollPane scrollPane = new JScrollPane(comboBox);
this.add(scrollPane, BorderLayout.NORTH);
CustomTextField customTextField = new CustomTextField();
this.add(customTextField, BorderLayout.CENTER);
JButton button = new JButton("press");
final JPopupMenu menu = new JPopupMenu("Menu");
menu.add(new JMenuItem("Test"));
button.setComponentPopupMenu(menu);
this.add(button, BorderLayout.SOUTH);
pack();
setVisible(true);
}
class CustomTextField extends JTextField implements FocusListener {
private CustomPopup customPopup = new CustomPopup();
public CustomTextField() {
this.addFocusListener(this);
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "VK_UP");
this.getActionMap().put("VK_UP", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
setPopupSize();
customPopup.show(CustomTextField.this, CustomTextField.this.getX(), CustomTextField.this.getY() + CustomTextField.this.getHeight());
customPopup.setSelectedIndex(0);
}
});
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "VK_DOWN");
this.getActionMap().put("VK_DOWN", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
setPopupSize();
customPopup.show(CustomTextField.this, CustomTextField.this.getX(), CustomTextField.this.getY() + CustomTextField.this.getHeight());
customPopup.setSelectedIndex(0);
}
});
}
public void setPopupSize() {
customPopup.setPopupSize(new Dimension(this.getWidth(), 110));
}
#Override
public void focusGained(FocusEvent e) {
}
#Override
public void focusLost(FocusEvent e) {
}
class CustomPopup extends JPopupMenu {
String[] values = new String[]{"Value1", "Value2", "Value3", "Value4", "Value5", "Value6", "Value7",
"Value8","Value9", "Value10", "Value11", "Value12", "Value13", "Value14", "Value15", "Value16",};
JList<String> list = new JList<>(values);
JScrollPane scrollPane = new JScrollPane(list);
public int index = 0;
public CustomPopup() {
this.setLayout(new GridLayout(0,1));
this.add(scrollPane);
this.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
if(customPopup.index > 0)
customPopup.setSelectedIndex(--customPopup.index);
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
if(customPopup.index < customPopup.getListSize()-1)
customPopup.setSelectedIndex(++customPopup.index);
}
}
});
this.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
index=0;
}
});
pack();
}
public void setSelectedIndex(int index) {
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
requestFocus();
}
public int getListSize() {
return values.length;
}
}
}
}
//customPopup.setVisible(true);
customPopup.show((JComponent)e.getSource(), 0, 20);
You should be using the show(...) method to show the popup. This must add some listeners to the popup so you will no longer need the FocusListener on the text field.
However, now this is a different problem. The text field loses focus so the Action never get invoked. That would be ok, but the JList never gains focus so it doesn't respond to the up/down keys unless you click on the list box first. I'm not sure what the problem is here.
Maybe you can try to make the popup, scrollpane and list all non-focusable so that focus remains on the text field?
'Focus', which is admittedly a slightly ambiguous term, generally applies to a component, not to an entire window. We think of the "window with focus", but I think what we really mean is "the current window, the one which contains the focus." I would not expect focus_lost to be called if I moved the window (aka JFrame) itself.
Another way to think of it; if I had a text field, clicked in it, and typed a letter or two, I would see those letters in that text field. If I then moved the window slightly and typed another letter or two, I would still expect those letters to appear in that field. It still has focus, and never lost it.