ActionListener principles - java

I am trying to find basic principles of adding action to JButton or other components. Here is what I am doing and what am I getting.
I have created a class named : Ali which has a main method in it, inside the main method Instantiate another method called: MainFrame and Whatever components I have I put in here.
I have created a simple button here, registered that with ActionListener interface, and I wrote an actionPerformed() method for that. Very simple and easy. But, somehow this program giving an error to me.
Here is the simplified codes and and errors.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Ali{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
JFrame frame = new MainFrameAli2("MainFrameAli2");
frame.setSize(400,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
And here is the MainFrameAli2 class
public class MainFrameAli2 extends JFrame implements ActionListener {
public MainFrameAli2(String title){
super(title);
// set layout manager
setLayout(new BorderLayout());
// create swing component
JTextArea textArea = new JTextArea();
JButton button = new JButton("click");
// add swing components to content pane
Container c = getContentPane();
c.add(textArea, BorderLayout.NORTH);
c.add(button, BorderLayout.SOUTH);
// add behavior
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
System.out.println("Clicked");
}
});
}
}
Now the problem is code is not running, here is the error:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problems:
The public type MainFrameAli2 must be defined in its own file
The type MainFrameAli2 must implement the inherited abstract method ActionListener.actionPerformed(ActionEvent)
And, if I write the code like below, everything is working OK.
// add behavior
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
System.out.println("hooyt");
}
}
Why it is not working in the first case and working in second case?

so, why it is not working in the first case and working in second case.?
Like the compiler message says, in the first example you didn't implement the ActionListener interface in your MainFrameAli2 class.
You created an anonymous inner class which implements the ActionListener interface. This is not the same thing as having your class implement the interface.
In the second example your class does implement the ActionListener.
If the first example you could have done:
//public class MainFrameAli2 extends JFrame implements ActionListener {
public class MainFrameAli2 extends JFrame {

Related

Unable to implement mouse listener

I am trying to implement mouse listener however I can not seem to get it to work. My code doesnt have any errors, but when I click on the frame I I can not get a message to print out. I have tried extending the class HandleClassOne to viewOne, but that also wouldn't work. Any thoughts?
The main class creates a frame and then creates an instance of viewOne on the frame.
public class main{
protected static JFrame window;
public static void main(String args[]){
window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400,400);
window.setVisible(true);
new viewOne(window);
}
}
The viewOne class adds a panel and a label to a frame. It also adds a mouse listener to the panel.
public class viewOne {
private static JPanel panel1;
private static JLabel label1;
public viewOne(JFrame frame) {
panel1 = new JPanel();
label1 = new JLabel("View One");
panel1.add(label1);
frame.add(panel1);
panel1.setBackground(Color.red);
frame.validate();
}
public static void mouseAdd() {
HandleClassOne handle = new HandleClassOne();
panel1.addMouseListener(handle);
panel1.addMouseMotionListener(handle);
}
public static void main(String[] args) {
mouseAdd();
}
}
The HandleClassOne class should print out a message when the panel created in viewOne is clicked.
public class HandleClassOne extends main implements MouseListener, MouseMotionListener {
public void mouseClicked(MouseEvent e) {
System.out.println("mouse clicked");
}
}
While you have defined the function mouseAdd(...) I don't see you calling it.
Try (within the constructor)
public viewOne(JFrame frame) {
...
mouseAdd();
...
}
naturally, you'll need to do this after the panel1 is set.
Note that there are other issues, too
You don't invoke presenting the JFrame properly within your main function in your main class. Look up a basic tutorial on Java Swing, where it talks about the event dispatch thread and the requirements to not present within your program's main thread of execution.
You have an additional main function in your viewOne class, which is not how these things are wired up.
You added the mouseAdd() method (which is responsible for registering the mouse listener) inside the main method of viewOne class.
Please keep in mind that main method only gets called whenever you are running it as entry point class for your application. Here you have main class to act as an entry point.
You kept main method in viewOne class as well and it will get called only when you are running it as an individual piece (not along with main class).
To fix the issue here, keep your mouseAdd() method call inside viewOne() constructor as constructor gets called every time whenever object is getting created.
public viewOne(JFrame frame) {
panel1 = new JPanel();
label1 = new JLabel("View One");
panel1.add(label1);
frame.add(panel1);
panel1.setBackground(Color.red);
mouseAdd();
frame.validate();
}

Storing JFrame output into a String in the Main Program

It seems to me that so far, everything that happens within JFrame stays within JFrame. (Probably should have gotten into JavaFX instead of Swing)
Let's say you have a JFrame Class (gui_frame) that utilizes JButtons with a nested class named HandlerClass that implements ActionListener, as shown below:
public class gui_frame extends JFrame {
private JButton button1;
public gui_frame() {
super("Title");
setLayout(new FlowLayout());
button1 = new JButton("Hello");
add(button1);
HandlerClass handler = new HandlerClass();
button1.addActionListener(handler);
}
private class HandlerClass implements ActionListener{
public void actionPerformed(ActionEvent e){
//insert code here
}
}
}
And then you have the main code, which calls upon this gui_frame class.
public class main {
public static void main(String[] args){
//insert some unrelated code here
gui_frame gf = new gui_frame();
gf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gf.setSize(400,75);
gf.setVisible(true);
String button_name;
//insert some code that uses button_name
}
}
Essentially, I'm trying to store the name of the button in the JFrame class gui_frame (in this case "Hello"), AFTER BEING CLICKED, into the String button_name in the main class, during run time.
Is this possible? What do I have to insert into the actionPerformed method in the gui_frame, in order to make this happen?
There's a few ways that you could do this:
implement the ActionListener as a lambda in the main class (btw, that should be capitalized, i.e. "Main"), and pass the lambda to the gui_frame class (again, that should be "GuiFrame"), and have the GuiFrame class apply the listener to the button
create an interface for the GuiFrame class to use to notify the Main class that the button has been clicked (and the name of the button). Have the Main class implement that interface, and then pass the instance of Main to the GuiFrame class. Then have the GuiFrame's ActionListener call the method in the Main class' interface to notify it.
Store the name of the last clicked button in the GuiFrame class, and have the Main class ask for it when it needs it (if it doesn't need to know when the button is clicked).

What is the keyword "this" referring to if it is given as an argument

I know when to use the keyword "this" for fields and constructors but I'm not sure when it is passed as an argument
import javax.swing.*;
import java.awt.event.*;
public class SimpleGui implements ActionListener {
JButton button;
public static void main (String[] args) {
SimpleGui gui = new SimpleGui();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
button = new JButton("click me");
button.addActionListener(this);
frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
button.setText("I've been clicked!");
}
}
The line button.addActionListener(this); means:
Add a listener to actions performed on the button object
Make the listener the current instance of SimpleGui within context (SimpleGui happens to implement the ActionListener interface)
So when the button is clicked, SimpleGui#actionPerformed should be invoked.
Whenever a button is presses to get a callback, we need to attach a listener to that button, here in your example that is done using following line,
button.addActionListener(this);
addActionListener() requires to pass a instance which implements ActionListener interface.
And here SimpleGui is a ActionListener as it implements that interface. Hence in SimpleGui you are writing,
button.addActionListener(this);
where this is instance of SimpleGui which implements ActionListener
This is a keyword which means the instance of the class,
in your class
public class SimpleGui implements ActionListener {
this is an instance of the SimpleGui, it could be as well an object (any) that is implementing the actionListener
If you call a method that accepts this, it is because
this argument is an object of the SimpleGui class, or even better, is an object (no matter which one) that implements the ActionListener.

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

Difficulty removing all components from a Jpanel

G'day all,
I am coding a main menu for a project. The menu displays properly. I have also set up ActionListeners for the three buttons on the menu.
What I wish to do is reuse the JPanel for a new set of radio buttons when the user chooses "Start a New Game".
However, coding ActionPerformed to remove the existing components from the JPanel has me stumped. I know removeAll is somehow important, but unfortunately NetBeans informs me I cannot call it on my mainMenu JPanel object within ActionPerformed. So i have commented it out in my code below, but left it in so you can see what I am trying to do.
Your thoughts or hints are appreciated.
Here is my main code:
public class Main {
public static void main(String[] args) {
MainMenu menu = new MainMenu();
menu.pack();
menu.setVisible(true);
}
}
Here is my mainMenu code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainMenu extends JFrame implements ActionListener {
JButton startNewGame = new JButton("Start a New Game");
JButton loadOldGame = new JButton("Load an Old Game");
JButton seeInstructions = new JButton("Instructions");
public MainMenu() {
super("RPG Main Menu");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainMenu = new JPanel();
mainMenu.setLayout(new FlowLayout());
startNewGame.setMnemonic('n');
loadOldGame.setMnemonic('l');
seeInstructions.setMnemonic('i');
startNewGame.addActionListener(this);
loadOldGame.addActionListener(this);
seeInstructions.addActionListener(this);
mainMenu.add(startNewGame);
mainMenu.add(loadOldGame);
mainMenu.add(seeInstructions);
setContentPane(mainMenu);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == startNewGame) {
// StartNewGame code goes here
// mainMenu.removeAll();
}
if (source == loadOldGame) {
// LoadOldGame code goes here
}
if (source == seeInstructions) {
// Quit code goes here
}
}
}
Consider using a CardLayout instead, which manages two or more components (usually JPanel instances) that share the same display space. That way you don't have to fiddle with adding and removing components at runtime.
You need mainMenu to be a member variable:
public class MainMenu extends JFrame implements ActionListener {
JButton startNewGame = new JButton("Start a New Game");
JButton loadOldGame = new JButton("Load an Old Game");
JButton seeInstructions = new JButton("Instructions");
JPanel mainMenu = new JPanel();
Why do you feel the need to re-use this object?
You don't have a reference to mainMenu actionPerformed use. If you declare mainMenu with the buttons. It would work.
The problem is that the actionPerformed method is trying to call the JPanel mainMenu which is out of scope, i.e. the mainMenu variable is not visible from the actionPerformed method.
One way to get around this is to have the JPanel mainMenu declaration in the class itself and make it an instance field which is accessible to all instance methods of the class.
For example:
public class MainMenu extends JFrame implements ActionListener
{
...
JPanel mainMenu;
public MainMenu()
{
...
mainMenu = new JPanel();
...
}
public void actionPerformed(ActionEvent e)
{
...
mainMenu.removeAll();
}
}
Avoid attempting to "reuse" stuff. Computers are quite capable of tidying up. Concentrate on making you code clear.
So instead of attempting to tidy up the panel, simply replace it with a new one.
Generally a better way to write listeners is as anonymous inner classes. Code within these will have access to final variables in the enclosing scope and to members of the enclosing class. So, if you make mainMenu final and you ActionListeners anonymous inner classes, your code should at least compile.
Also don't attempt to "reuse" classes. Try to make each class do one sensible thing, and avoid inheritance (of implementation). There is almost never any need to extend JFrame, so don't do that. Create an ActionListener for each action, rather than attempting to determine the event source.
Also note, you should always use Swing components on the AWT Event Dispatch Thread. Change the main method to add boilerplate something like:
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
runEDT();
}});
}

Categories

Resources