How to properly format an ActionEvent so JButtons will work - java

I have set up some ActionListeners, however only 'Takeoff' works. The other buttons do not work when they are clicked. When they are clicked, nothing happens.
I have tried to create a new ButtonHandler, but that did not work.
ButtonListener l = new ButtonListener();
JButton takeoff = new JButton("Takeoff");
takeoff.addActionListener(new ButtonHandler());
takeoff.addActionListener();
grid[0][2].add(takeoff);
JButton land = new JButton("Land");
land.addActionListener(new ButtonHandler());
grid[1][2].add(land);
JButton forward = new JButton("Forward");
forward.addMouseListener(new MouseHandler(l));
forward.addActionListener();
grid[2][1].add(forward);
JButton left = new JButton("Left");
left.addMouseListener(new MouseHandler());
left.addActionListener(new ButtonHandler());
left.addActionListener();
grid[3][0].add(left);
takeoff.addActionListener(l);
land.addActionListener(l);
forward.addActionListener(l);
backward.addActionListener();
left.addActionListener(l);
right.addActionListener(l);
turnLeft.addActionListener(l);
turnRight.addActionListener(l);
up.addActionListener(l);
down.addActionListener(l);
stop.addActionListener(l);
What I want to do is move the robot drone in the correct direction, rather than just letting it sit still.
I am not sure if this part will help, but I have where my ButtonHandler implements ActionListener.
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String button = e.getActionCommand();
if (button.equals("Takeoff")) {
RobotModel.takeoff();
}
else if (button.equals("Land")) {
RobotModel.land();
}
else if(button.equals("Left")) {
RobotModel.left();
}
}
}

You could use the actionCommand to invoke a method via reflection, e.g.
private void init() {
JButton left = new JButton("Go left");
// This
left.setActionCommand("left");
left.addActionListener(new MethodCallActionHandler());
// OR that
left.addActionListener(new MethodCallActionHandler("left"));
}
private void left() {
// go left...
}
private class MethodCallActionHandler implements ActionListener {
private String methodName;
private MethodCallActionHandler() {
super();
}
private MethodCallActionHandler(String methodName) {
this.methodName = methodName;
}
public void actionPerformed(ActionEvent e)
{
String button = methodName != null ? methodName : e.getActionCommand();
SurroundingClass.this.getClass().getMethod(button, new Class[] {}).invoke(SurroundingClass.this);
}
}
You could also pass the action command as String to the MethodCallActionHandler.

You can inherit the Action Listener class into your current class and then add the required methods. Then you can do takeoff.add(this)... etc.
Also nowhere are you setting the action command, that is done in the button settings.
When you are setting
String button = e.getActionCommand();
That is not what is being set when you do
JButton button = new JButton("Takeoff"); <-- This is the text associated with the button
button.setActionCommand("Takeoff");
and then it should work.

Related

JAVA After adding a seccond button and its actionListener, actions get executed twice

After adding a listener to a second button, the first created button executes twice the same action:
public class ControladorTablaMaterial implements ActionListener {
private VistaTablaMaterial vistaTablaMaterial;
private JPanel jContentPane = null;
private JScrollPane scrollPane = null;
private JTable tablaMaterial;
private JButton mostrarElementoButton;
private JButton eliminarElementoButton;
private ModeloTablaMaterial modeloTablaMaterial;
public ControladorTablaMaterial(ArrayList<Material> coleccionMaterial, ActionListener listener) {
String[] cabecera = {"Material", "Titulo"};
this.vistaTablaMaterial = new VistaTablaMaterial(cabecera, coleccionMaterial);
setupVistaTablaMAterial(listener);
}
private void setupVistaTablaMAterial(ActionListener listener) {
this.scrollPane = vistaTablaMaterial.getScrollPane();
this.tablaMaterial = vistaTablaMaterial.getTablaMaterial();
this.modeloTablaMaterial = vistaTablaMaterial.getModeloTablaMaterial();
this.mostrarElementoButton = vistaTablaMaterial.getMostrarElementoButton();
this.eliminarElementoButton = vistaTablaMaterial.getMostrarElementoButton();
this.initListeners(listener);
}
private void initListeners (ActionListener listener) {
getMostrarElementoButton().addActionListener(listener);
getEliminarElementoButton().addActionListener(listener);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
Everything works fine if I delete the line:
getEliminarElementoButton().addAtionListener(listener);
but of course I need that button to be listened to too.
Inside the listener class, in the actionPerformed(actionEvent e) method, I use the following code to differentiate both buttons:
if (e.getSource().equals(this.getControladorTablaMaterial().getMostrarElementoButton())) {
That seems to work fine except for this frame. Any guess?
Off topic: why isn't the code indentation working properly on Stackoverflow's editor?
The problem is in these lines:
this.mostrarElementoButton = vistaTablaMaterial.getMostrarElementoButton();
this.eliminarElementoButton = vistaTablaMaterial.getMostrarElementoButton();
That you are getting the same button for both.

triggering an action of button from another class in the main method

Hello while I was following a tutorial I have learnt a way to trigger response in the main class from a click of a button in another class.
So what I have done is that I have a ToolBar class with some code as below
private JButton helloButton;
private JButton goodbyeButton;
private StringListener textListener;
public Toolbar() {
setBorder(BorderFactory.createEtchedBorder());
helloButton = new JButton("Hello");
goodbyeButton = new JButton("Goodbye");
helloButton.addActionListener(this);
goodbyeButton.addActionListener(this);
setLayout(new FlowLayout(FlowLayout.LEFT));
add(helloButton);
add(goodbyeButton);
}
public void setStringListener(StringListener listener) {
this.textListener = listener;
}
#Override
public void actionPerformed(ActionEvent e) {
JButton clicked = (JButton) e.getSource();
if (clicked == helloButton) {
if (textListener != null){
textListener.textEmitted("Hello\n");
}
//textPanel.appendText("Hello\n");
} else {
if (textListener != null){
textListener.textEmitted("Goodbye\n");
//textPanel.appendText("Goodbye\n");
}
}
}
Then in StrinListener Interface I have
public interface StringListener {
public void textEmitted (String text);
}
Finally in main I get the two together by
toolbar.setStringListener(new StringListener (){
#Override
public void textEmitted(String text) {
textPanel.appendText(text);
}
});
what I am curious about is that why does clicking a button trigger response in main method "every time" I click?
so the click is being passed onto textemitted method in StringListener interface and that is received by toolbar.setStringListener in main method. But what is invoking it to work over and over whenever I click the button?
shouldn't the code be read only once unless there is while loop or another loop of some sort?
Thanks
my main class
public MainFrame() {
super("Hello World");
setLayout(new BorderLayout());
textPanel = new TextPanel();
btn = new JButton("Click Me!");
toolbar = new Toolbar();
formPanel = new FormPanel();
toolbar.setStringListener(new StringListener (){
#Override
public void textEmitted(String text) {
textPanel.appendText(text);
}
});
formPanel.setFormListener(new FormListener(){
public void formEventOccurred(FormEvent e){
String name = e.getName();
String occupation = e.getOccupation();
textPanel.appendText(name + ": " + occupation + "\n");
}
});
add(toolbar, BorderLayout.NORTH);
add(textPanel, BorderLayout.CENTER);
add(formPanel, BorderLayout.WEST);
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
It is behaving as expected.
Remember that when you set the textListener, the Toolbar class holds on to an instance variable (of the textListener), and therefore it is kept alive as long as your program is running or until the toolbar object is destroyed. Just because it is an anonymous inner class doesn't mean that the object is destroyed after the method textEmitted is ran once.

why doesnt my actionListener work with my jcomboBox

I know I'm missing something very simplem but for the life of me I can't see it. All I want to do is get "Paris" from the combo box, and when the button is pressed, show that "Paris" is selected.
public class assignment2try2 implements ActionListener {
private JComboBox HolidayLocation;
private JComboBox HolidayDuration;
private JButton PriceCheck;
public static void main(String[] args) {
JLabel Location = new JLabel(" Where do you want to go ? ");
String[] HolidayLocations = {" ","Paris", "Crete", "Croatia"};
JComboBox<String> LocationBox = new JComboBox<String>(HolidayLocations);
LocationBox.setEditable(false);
LocationBox.setPreferredSize(new Dimension( 160, 20 ));
//LocationBox.setSelectedIndex(4);
LocationBox.addActionListener(LocationBox);
JButton PriceCheck = new JButton("Check Availability");
PriceCheck.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("button works");
//if(LocationBox.getSelectedItem().equals(HolidayLocations))
{
//System.out.println("paris selected");
}
}
});
}
}
EDIT: I just now noticed that your class implements ActionListener. With the below solution, you can remove the implements-statement from your code.
To fix your issues with the String having to be final, make a private class:
private class MyListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println(locationBox.getSelectedItem() + " selected.");
}
}
Then, replace
PriceCheck.addActionListener(new ActionListener() { ... });
with
PriceCheck.addActionListener(new MyListener());
This should be able to print out the selected value after the button is pressed.
Note: I changed your variable name from LocationBox to locationBox to comply with naming conventions.

How to make an action command for same buttons

I have here just a snip of code for my button:
up = new JButton(new ImageIcon("more_buttons\\up3.png"));
up.setBackground(new Color(224,223,227));
up.setPreferredSize(new Dimension(5,15));
up.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
value1000++;
if(value1000>0)
{
number.setText(value1000+"");
down.setEnabled(true);
}
}
});
down = new JButton(new ImageIcon("more_buttons\\down3.png"));
down.setBackground(new Color(224,223,227));
down.setPreferredSize(new Dimension(5,15));
down.setEnabled(false);
down.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
value1000--;
if(value1000>0)
{
number.setText(value1000+"");
}
if(value1000==0)
{
number.setText(value1000+"");
down.setEnabled(false);
}
}
});
I'm wondering if I can make an action command for this button so that I won't have to repeat this code throughout my program. I only have to call the function like buttonaction(e) or something like that. I'm not used to creating action command but I have used it before but only for appending text. I'm not sure how to do that with a function like this. Is it possible? Or is there a more efficient way to do this?
You can add the same ActionListener to multiple buttons:
ActionListener al = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// You can check which button was pressed and act accordingly
// simply by checking the event source:
if (e.getSource() == button1)
System.out.println("Button1 was pressed.");
else if (e.getSource() == button2)
System.out.println("Button2 was pressed.");
}
};
button1.addActionListener(al);
button2.addActionListener(al);
To remove boiler plate code, You need to at least implement an ActionListener in your class
samaple:
public class myClass implements ActionListener
It will generate an actionPerformed method After you need to add actionCommand in your button so when you click a button it will recognize it that you pressed that button
sample:
down.setActionCommand("down");
down.addActionListener(this);
up.setActionCommand("up");
up.addActionListener(this);
in the actionPerformed method
#Override
public void actionPerformed(ActionEvent evt)
{
String actionCommand = evt.getActionCommand(); //get the actionCommand and pass it to String actionCommand
switch(actionCommand) { //switch statement for each of the action command
case "down":
//down button command here
break;
case "up":
//up button command here
}
}
Take a look at How to use Actions
public abstract class AbstractNumberValueAction extends AbstractAction {
private NumberModel model;
private JTextField numberField;
private int delta;
public ValueAction(NumberModel model, JTextField numberField, int delta) {
this.model = model;
this.numberField = numberField;
this.delta = delta;
}
public void actionPerformed(ActionEvent evt) {
int value1000 = model.updateValue(delta);
if(value1000>0)
{
numberField.setText(value1000+"");
}
if(value1000==0)
{
numberField.setText(value1000+"");
setEnabled(false);
}
}
}
public class UpAction extends AbstractNumberValueAction {
public ValueAction(NumberModel model, JTextField numberField) {
this(model, numberField, 1);
putValue(SMALL_ICON, new ImageIcon("more_buttons\\up3.png"));
}
}
public class DownAction extends AbstractNumberValueAction {
public ValueAction(NumberModel model, JTextField numberField) {
this(model, numberField, -1);
putValue(SMALL_ICON, new ImageIcon("more_buttons\\down3.png"));
}
}
Which could then simply be applied as
up = new JButton(new UpAction(model, number));
down = new JButton(new DownAction(model, number));
For example...
(ps- NumberModel would be a simple class that controlled the underlying value to make is simpler to manage ;))

actionlistener callback to another class

I have a class LabelTextField which does as it indicates, it create a label followed by text field. I want this class to act as JTextField does, ie responding to actionPerformed when an action listener is added. I am adding an action listener with LabelTextField so the JTextField in this class will need to receive the callback and forward on the LabelTextField object name and not the JTextField object name.
I have show a simple JTextField and how it works, the LabelTextField is also there and how I expect to use it.
I have provided a code snippet of what I want to do.
I am having trouble with this type of callback and detail information would be useful.
//
class C_one extends JPanel
{
private JTextField mjtfOne;
private LabelTextField m_nameFind;
public C_one ()
{
setLayout(new FlowLayout());
mjtfOne = new JTextField(20);
mjtfOne.addActionListener(this);
m_nameFind = new LabelTextField("Name", 20);
m_nameFind.addActionListener(this);
add(mjtfOne);
add(m_nameFind);
}
// This is called when return is pressed in either object.
public void actionPerformed(ActionEvent ae)
{
// This works.
if (ae.getSource() == mjbnOne) {
System.out.println("Text field one!");
// ****** This doesn't work. *****
} else if (ae.getSource() == m_nameFind) {
System.out.println("Label Text Field name");
}
}
}
//
// This create a label and textfield as a widget.
class LabelTextField extends JPanel
{
private JTextField mjtf;
private ActionListener mal;
public LabelTextField(String label, int textfieldWidth)
{
setLayout(new FlowLayout());
JLabel lbl = new JLabel(label);
add(lbl);
mjtf = new JTextField(textfieldWidth);
add(mjtf);
}
// The caller of this class will call this as he would for
// JTextField.
public void addActionListener(ActionListener al)
{
mjtf.addActionListener(this);
mal = al;
}
// This will receive the return from JTextField and needs
// to forward this on to calling class with caller object
// not mjtf.
//
// Problem: I can not figure out how to save caller object
// name so when this is called I can forward it on just like
// what JTextField would have done, ie caller can use
// ae.getSource() == m_nameFind.
public void actionPerformed(ActionEvent ae)
{
mal.actionPerformed(ae); // This does call the caller.
}
}
the value of ae.getSource() will be mjtf, because that is the component that generated the original ActionEvent.
If you want to have the source of the event to be m_nameFind, i.e. your custom LabelTextField object, you need to set it manually:
public void actionPerformed(ActionEvent ae)
{
ae.source=this; // this makes it look like the LabelTextField generated the event
mal.actionPerformed(ae);
}
Is this what you want to do?
--
edit
Thanks #Madprogrammer.. Perhaps you should recreate the ActionEvent like this
public void actionPerformed(ActionEvent ae)
{
mal.actionPerformed(new ActionEvent(this, ae.getID(),
ae.getCommand(), ae.getWhen(), ae.getModifiers() ));
}
Since you can't change the source of the ActionEvent, you need to create a new ActionEvent:
public void actionPerformed(ActionEvent e)
{
e = new ActionEvent(
this,
ActionEvent.ACTION_PERFORMED,
e.getActionCommand(),
e.getWhen(),
e.getModifiers());
mal.actionPerformed(e);
}

Categories