JButton ActionListener not responding - java

I couldn't find the answer anywhere else online, so I came here. I apologize in advance if the mistake in my code is very obvious; I'm still quite new to java swing. Here's what's going on: I have created a JButton named toggleElevators, and I want it to change text when clicked. I have already created an ActionListener and added it to toggleElevators. All I want right now is for the JButton to change text when clicked from Click me to Clicked.
First, here's a picture of what the JFrame looks like when executed:
NOTE: There is a third class, but it is purely for drawing the picture on the left. It has nothing to do with the GridLayout or the JButton.
Run class (created frame and adds toggleElevators JButton:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
public class Run extends Input{
Input i = new Input();
public static void main(String[] args) {
new Run();
}
public Run() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Elevators");
frame.setLayout(new GridLayout(0, 3));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Elevators(Color.MAGENTA, true));
frame.add(new Elevators(Color.ORANGE, false));
frame.setSize(800,600);
frame.setResizable(false);
frame.getContentPane().add(toggleElevators); //adds toggleElevators button to JFrame
i.addButtonListeners(); //calls method defined in Input class, which adds the ActionListener to the toggleElevators button
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Input class (creates toggleElevators JButton and its ActionListener):
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
public class Input {
JButton toggleElevators = new JButton("Click me.");
public void addButtonListeners() {
toggleElevators.addActionListener(new toggleElevatorsListener());
}
class toggleElevatorsListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
toggleElevators.setText("Clicked.");
System.out.println("ActionListener called."); //I know the ActionListener is not being called because this line is not being printed out in the console
}
}
}

Your Run class extends Input, but also HAS an Input named i. You're adding this.toggleElevators to the frame, but you're adding a listener to i.toggleElevators.
Remove the i field from your class. I would also forget completely about defining and extending an Input class. It doesn't serve any purpose, and seems to confuse more than help you.

You create a new Input in your Run class, while the Run class also extends Input.
When you call i.addButtonListeners(); the action listeners are added on the toggleElevators from i and not on the toggleElevators you inherited from the Input class.
Try addButtonListeners().

Your Run class extends Input. Therefore it has its own toggleElevators which is the one it sets in the frame. However, i has is own toggleElevators where it sets the event listeners. So they are not set on the one in the frame but on one that never gets used.
You can simply delete the i object. As Run extends Input, it can call the method directly, and then the listener will be added to its own toggleElevators.

Related

Why can´t I click on the JButtons?

Hey I am a beginner and I have wrote the following code in java, but I can´t click on the JButtons. The program includes three clases - Main, Frame and Actionhandler. My goal was to create a Frame with two buttons: Singleplayer and Mulitplayer. I wanted to test if they work, but I can´t click them. Can anyone help me please?
This is the Main class:
public class Main {
public static void main (String [] args) {
new Frame ();
}
}
This is the Frame class:
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Frame extends JFrame {
public static Object multi;
public static Object single;
Frame() {
// Frame
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLocationRelativeTo(null);
//Layout in Frame
this.setLayout(new GridLayout(2,1));
this.setVisible(true);
// Buttons in Main Menu
JButton single = new JButton("Singleplayer");
JButton multi = new JButton("Multiplayer");
// specify single button
single.setBounds(200,100,250,80);
single.setForeground(Color.GREEN);
single.setBackground(Color.LIGHT_GRAY);
single.setOpaque(true);
single.setBorder(BorderFactory.createLineBorder(Color.BLACK));
single.setFont(new Font("Comic Sans",Font.BOLD,25));
single.addActionListener(new ActionHandler());
//specify multi button
multi.setBounds(800,100,250,80);
multi.setForeground(Color.GREEN);
multi.setBackground(Color.GRAY);
multi.setOpaque(true);
multi.setFont(new Font("Comic Sans",Font.BOLD,25));
multi.setBorder(BorderFactory.createLineBorder(Color.BLACK));
multi.addActionListener(new ActionHandler());
// add Buttons to Frame
this.add(single);
this.add(multi);
}
}
This is the ActionHandler class:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ActionHandler implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == Frame.multi) {
System.out.println("You have clicked on Singleplayer");
if(e.getSource() == Frame.single) {
System.out.println("You have clicked on Multiplayer");
}
}};
}
You can click on the buttons fine. They just won't do anything because of how you've wired the program:
public class Frame extends JFrame {
public static Object multi; // this is null
public static Object single; // and so is this
Frame() {
// Frame
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLocationRelativeTo(null);
//Layout in Frame
this.setLayout(new GridLayout(2,1));
this.setVisible(true);
// Buttons in Main Menu
JButton single = new JButton("Singleplayer"); // this is a new *local* variable
JButton multi = new JButton("Multiplayer"); // and so is this:
You are initializing local variables that have the same name as your static class fields, and you're leaving the same static class fields null, a situation known as "variable shadowing", and so in your listeners, you check if the source is the null static field. Which won't work.
So in your listener:
public void actionPerformed(ActionEvent e) {
if(e.getSource() == Frame.multi) {
You're testing if a null variable is the button that was pressed, and this will not work.
One simple solution is to not re-declare the multi and single variables, to assign your JButtons to these public static fields by changing this:
JButton single = new JButton("Singleplayer");
JButton multi = new JButton("Multiplayer");
to this:
single = new JButton("Singleplayer");
multi = new JButton("Multiplayer");
This would sort-of work. You'd have do do some casting to add these JButton objects to the container since the variables are Object, not JButton. But this would be a bad idea because you'd be throwing out the OOPs baby with the bathwater, discarding encapsulation completely.
Best not to throw out OOPs rules with public static (non-constant) fields and instead work with them. Better to use constant Strings to be passed into your JButtons and then test for them using the ActionEvent's actionCommand property:
public class Frame extends JFrame {
public static String SINGLE_PLAYER = "Single Player";
public static String MULTI_PLAYER = "Multi Player";
Frame() {
// Frame
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLocationRelativeTo(null);
//Layout in Frame
this.setLayout(new GridLayout(2,1));
this.setVisible(true);
// Buttons in Main Menu
JButton single = new JButton(SINGLE_PLAYER); // this is a new *local* variable
JButton multi = new JButton(MULTI_PLAYER); // and so is this:
in the listener:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ActionHandler implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals(Frame.MULTI_PLAYER)) {
System.out.println("You have clicked on Multi Player");
} else {
// ...
}
}};
}
Other problems with your code include:
Don't name your class Frame since this clashes with the name of class in the core Java library, java.awt.Frame. Name it something unique to avoid confusion
Avoid setting bounds, sizes and such. Let the GUI, its layout managers and component preferred sizes do the sizing by calling pack() on the top-level window (JFrame, JDialog,...) after adding components
Call .setVisible(true) on the top-level window after adding all components.
This looks like it will display as a sub-window or dialog window, and you might want to show this portion of the GUI in a modal JDialog, not in a JFrame.

Access difficulty with ArrayList of panels with buttons

my question is: how do I get the object of my CustomPanel, so that I am able to access its fields (because in my real programm I have some more fields in there) and also am able to delete it from my ArrayList?
I don't know how I have to implement an ActionListener in the Class Window, to somehow get the Object in my Arraylist, which containes the button that got pressed.
Also I am wondering if I am somehow able to implement an ActionListener in the Class CustomPanel which can influence the behaviour of the Object which is an instance of my Class Window.
I have kind of the following code:
public class Window extends JFrame{
ArrayList<CustomPanel> aLCustomPanel = new ArrayList();
JPanel jp = new JPanel();
public Window() {
for(int i=0;i<5;i++){
aLCustomPanel.add(new CustomPanel());
//here I could put the code from the 1 edit - see below
jp.add(aLCustomPanel.get(i));
}
this.add(jp);
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Window().setVisible(true);
}
});
}
}
class CustomPanel extends JPanel {
private JButton button;
public CustomPanel(){
button = new JButton("button");
this.add(button);
}
public JButton getButton(){
return this.button;
}
}
my Code is much longer and weirder, so I tried to extract the (for this question) importing things.
Thanks for any help in advance!
edit:
for example: I would like to delete the object from the ArrayList, of which the button got pressed.
//imagine this comment in above code
aLCustomPanel.get(aLCustomPanel.size()-1).getButton().addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button_IwantToDeleteYou(e); //here I want to remove the panel, containing the button that got pressed from the above ArrayList, which is located in Class Window
}
});
edit2:
added a missing bracket and fixed some mistakes, code should be ok now.
Your code contained a few "gaps", i.e. missing code, which I filled in, as follows:
Added calls to [JFrame] methods setDefaultCloseOperation() and pack() and setLocationByPlatform(). I suggest you refer to the javadoc for those methods in order to understand what they do.
I set a layout manager for jp class member variable in your Window class.
Yes, you need to register an ActionListener with the JButton in class CustomPanel and that listener should reside in your Window class - the one that extends JFrame.
Here is my rewrite of your code. Note that I changed the name of class Window to CusPanel so as to distinguish between your class and java.awt.Window class. Not that it makes a difference, I just prefer not to use names of classes from the JDK.
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class CusPanel extends JFrame implements ActionListener {
private static final int COUNT = 5;
private ArrayList<CustomPanel> aLCustomPanel = new ArrayList<>();
private JPanel jp = new JPanel(new GridLayout(0, COUNT));
public CusPanel() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
for (int i = 0; i < COUNT; i++) {
aLCustomPanel.add(new CustomPanel(this));
// here I could put the code from the 1 edit - see below
jp.add(aLCustomPanel.get(i));
}
this.add(jp);
pack();
setLocationByPlatform(true);
}
public void actionPerformed(ActionEvent actionEvent) {
Object source = actionEvent.getSource();
if (source instanceof JButton) {
JButton button = (JButton) source;
Container parent = button.getParent();
jp.remove(parent);
jp.invalidate();
jp.repaint();
pack();
// aLCustomPanel.remove(parent); <- optional
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new CusPanel().setVisible(true);
}
});
}
}
class CustomPanel extends JPanel {
private JButton button;
public CustomPanel(ActionListener parent) {
button = new JButton("button");
button.addActionListener(parent);
this.add(button);
}
public JButton getButton() {
return this.button;
}
}
Note that after removing a CustomPanel, the GUI components need to be laid out again and the JFrame should also be resized accordingly. Hence in the actionPerformed() method, I call invalidate(), then repaint() and then pack(). I also think that if you remove a CustomPanel from the GUI, you should also remove it from the ArrayList, but hey, I still don't understand why you want to do this although I obviously don't know the whole story behind you wanting to do this in the first place.
Of-course, since each button (and each CustomPanel) looks exactly the same, you can't really know which button was removed. Again, I assume you see the big picture whereas I don't.

Java Swing JFrame dispose method

I would like some clarity on what is exactly happening here. Say I have these three methods and I continually hit the button again and again. Is this causing some kind of memory leak or chain of pointers that I am unaware of? My understand is that when a method ends any variables local to that method are cleaned up. This would include that "pointer" to the new JFrame then correct?
Again assume the user is clicking the button on each frame.
public class driver {
public static void main(String[] args) {
// TODO Auto-generated method stub
parentFrame pF = new parentFrame();
}
}
-
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class parentFrame extends JFrame {
private JFrame frame;
private JButton button;
public parentFrame() {
frame = new JFrame("Parent Frame");
frame.setSize(400, 400);
button = new JButton();
frame.add(button);
button.addActionListener(new buttonPress());
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void createChild() {
#SuppressWarnings("unused")
childFrame cF = new childFrame(); //The default constructor will display the frame
frame.dispose(); //How?
}
class buttonPress implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
createChild();
}
}
}
-
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class childFrame extends JFrame {
private JFrame frame;
private JButton button;
public childFrame() {
frame = new JFrame("Child Frame");
frame.setSize(400, 400);
button = new JButton();
frame.add(button);
button.addActionListener(new buttonPress());
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void createParent() {
parentFrame pF = new parentFrame(); //The default constructor will display the frame
frame.dispose(); //How?
}
class buttonPress implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
createParent();
}
}
}
I'm not sure what you mean by "I don't have to call super()", but if you want to avoid confusion, then either extend JFrame or use a variable in your class of type JFrame. You have both, and create the variable reference in the constructor, so that when JFrame frame = new parentFrame(); is executed, two JFrames are created: the one on which you have the new operator, and the one in the constructor of that object.
As for cleanup, when you execute setVisible(true); on a JFrame, it seems obvious to me that the JFrame reference gets put into the Swing system, and so the variable in your method (whether local or instance (or static)) is no longer the only reference. I think of dispose() as an instruction to the Swing framework that the code is done with this variable, clean up after it and remove all references to it. If you don't do that before you lose your own reference to the variable (e.g., if it were a local variable and you didn't do that before you exited the method), then you would lose your chance to call dispose. I suppose you could still get a reference from Swing somehow, and then call dispose on it.
You don't say whether you have evidence of a memory leak or or just trying to understand this code.
I have read your question, the answers and the comments. I advice you to review OOP basics to link your objects better. About the comment:
How can I create a new Frame in the parentFrame and then dispose of that frame but the child frame remains alive. Is control passed to the child frame?
Each JFrame is an independent instance of the JFrame object. You don't need to manually pass control. What you should do is define closing behaviour for each JFrame: A main frame on close will close the whole program (EXIT_ON_CLOSE), secondary frames can have other behaviour (HIDE_ON_CLOSE or DISPOSE_ON_CLOSE). You define this with:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I should advice you to go through the java tutorials and make sure you understand well about classes and instances before diving into swing. Start manually will help you understand better (I saw they told you this already but I agree on it). Keep on!

Unable to set size and location of button in java

I was just writing an application and i was not able to set location and size of button to desired values. whenever i open code the button comes at same location and with same size
Here is my code
public class main_class {
public static void main(String args[]){
Main_page mp = new Main_page();
mp.start();
}
}
Second file is:
import javax.swing.*;
import java.awt.*;
public class Main_page extends JPanel {
private static final long serialVersionUID = 1L;
public void start(){
JPanel panel1 = new JPanel();
panel1.setBackground(Color.pink);
JButton Button1 = new JButton("Programmer");
Button1.setSize(10, 100);
Button1.setLocation(200,500);
panel1.add(Button1);
JFrame frame1 = new JFrame("Main Window");
frame1.setSize(700,500);
frame1.setContentPane(panel1);
frame1.setResizable(false);
frame1.setVisible(true);
}
}
what is the problem.
What is the problem?
I'm so glad you asked that question. It's not just a matter of getting a Swing application to work. You must get the Swing application to work correctly so that you can add more functionality to your Swing application without your Swing application breaking.
I added a call to SwingUtilities invokeLater in the main method. This call ensures that the Swing components are defined and used on the Event Dispatch thread (EDT).
I changed the name of your class to MainPage to conform to Java standards for naming classes.
I implemented Runnable to make the invokeLater method parameter easier to define.
I removed the extends of JPanel. You use Swing components. The only reason to extend a Swing component is when you want to override one of the component methods. The only reason you extend any Java class is when you want to override one of the class methods.
I changed the name of your MainPage method to run.
I set a layout (FlowLayout) for your JPanel. You must always use a layout manager for your Swing components.
I made button1 lowercase. Java field names are lowercase, so you can easily differentiate them from class names.
I added a call to the JFrame setDefaultCloseOperation to your run method. Without this call, your Swing application will not stop executing when you close the window. After a while, you'll have dozens of copies of your Swing application running, with no easy way to stop them.
I added a call to the JFrame pack to let the JFrame expand or contract to fit the components, rather than be a fixed size.
Here's the revised code. I put the main method in the MainPage class to make it easier to paste the code.
package com.ggl.testing;
import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MainPage implements Runnable {
#Override
public void run() {
JPanel panel1 = new JPanel();
panel1.setBackground(Color.pink);
panel1.setLayout(new FlowLayout());
JButton button1 = new JButton("Programmer");
panel1.add(button1);
JFrame frame1 = new JFrame("Main Window");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.add(panel1);
frame1.pack();
frame1.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new MainPage());
}
}
if you want to set the size and location manually then you can use panel1.setLayout(null); as people have said in the comments this isn't recommended.

Java actionlistener doesn't work

I just started learning Java 1 week ago, and I'm a 100% totally beginner. In this code, I can't seem to be able to put an actionlistener/get one to work. I don't even know where/how/in what way to put it, despite reading dozens of tutorials. I've created a JFrame with a JPanel in it, and on the JPanel there's a button. So far so good (and working). But then, I want it to be so that if the button is clicked, another button appears. Thank you sooo much in advance!
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class Skeleton extends JFrame implements ActionListener {
public static void main(String[] args) {
//------------------------------------------------
JFrame frame = new JFrame("Skeleton");
JPanel panel = new JPanel();
frame.setContentPane(panel);
frame.setSize(600,600);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
JButton button = new JButton("This is a button.");
JButton button2 = new JButton("Hello");
panel.setLayout(null);
button.setBounds(20,20,200,25);
button2.setBounds(20,70,200,25);
panel.add(button);
//-------------------------------------------
button.addMouseListener(this);
}
public void ActionPerformed(ActionEvent e) {
System.out.println("Hello");
}
}
i will give you some advice
1) Don't implement ActionListener in top classes, use anonymous classes or private classes instead.
Example :
Anonymous class (also call Swing Actions)
myComponent.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
//code here
}
})
or
//inner class
public class Skeleton{
// in some part
private class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent evt){
//code here
}
}
}
2) Your code won't compile cause you are not implementing ActionListener interface
public void actionPerformed(ActionEvent evt) is the signature.
You have to addActionListener to your component
button.addActionListener(this);
3) Don't use null layout, cause you'll have a lot of problem if you want to add more components or resize windows cause you have to setBounds manually and it will be frustrating instead use [Layout Manager][1].
4) Try to not extends JFrame if is not necesary instead have a reference in your class, for example.
public class Skeleton{
private JFrame frame;
}
You need to add the actionlistener.
Register an instance of the event handler class as a listener on one or more components. For example:
yourdesiredcomponent.addActionListener(this);
For more details check the doc

Categories

Resources