How to access AbstractButton's method from anonymous inner class? - java

Here is my class:
public class ButtonPanel extends JPanel {
public ButtonPanel () {
makeButton ("button1");
makeButton ("button2");
makeButton ("button3");
}
void makeButton (String name) {
JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setText("I was clicked");
}
});
}
}
When the button is clicked, its text should change to "I was clicked". However, I don't know how to access the setText method. I tried button.setText("I was clicked") but this is not possible.

By making the reference of JButton as final, like :
void makeButton(String name)
{
final JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
button.setText("I was clicked");
}
});
}
Here is one related example :
Add action to a Button created by another Button
EDIT 1:
Here is one updated version of your code, that works as mentioned before :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonExample1 extends JPanel {
private JButton makeButton (String name) {
final JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
button.setText("I was clicked");
}
});
return button;
}
private void displayGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.add(makeButton("One"));
contentPane.add(makeButton("Two"));
contentPane.add(makeButton("Three"));
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ButtonExample1().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
EDIT 2 :
Here is the answer that tries to explain a reason, why you need to declare it as final
To answer your question, you need to understand the basics, as to how the JVM use to work.
When the classes are compiled which contain inner classes, the byte code which gets generated does not actually implement inner classes as a class within a class.
WHY THE ERROR : The local variable was accessed from an inner class, needs to declare it final
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
public foo()
{
final JMenu edit = new JMenu();
edit.getItem(0).addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
When you compile your this program, two files will be created, Foo.class and Foo$1.class. So now your problem comes, since the Second class i.e. foo$1.class doesn't know that Variable edit is present inside the First class i.e. foo.class.
So how to solve this problem ? What JVM does, is that, It makes a requirement for the developer to make the variable of an outer class to be declared as final.
Now this being done, now JVM quietly places a hidden variable with the name val$edit inside the 2nd compiled class file, here is the output as got from javap
Ouput for foo.class
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
public foo();
}
Now since, edit is local to the constructor, hence the output as above.
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final javax.swing.JMenu val$edit;
final foo this$0;
foo$1(foo, javax.swing.JMenu);
public void mouseClicked(java.awt.event.MouseEvent);
}
The Variable val$edit is assigned the same value which has been assigned to edit since now the compiler knows that the value cannot be changed as it has been declared final and hence it works this time.
Now what if I change the edit Variable from being Local to being Instance. Now the object of the class knows everything about this variable edit, if it gets changed. So changing the above program likewise we get :
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
JMenu edit = new JMenu();
public foo()
{
edit.getItem(0).addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
Here in this case, we are not suppose to declare and define it as being final, because in this case since the Variable being Local to the whole class, the Variable is send to the Inner Class along with the Object Reference i.e. this
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
javax.swing.JMenu edit;
public foo();
}
Here is how the Variable is send in this case i.e. this$0 :
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final foo this$0;
foo$1(foo);
public void mouseClicked(java.awt.event.MouseEvent);
}
Seems like that the interpretation, how this situation works, according to me.
Just now I found this wonderful explanation on the internet regarding Mystery of Accessibility in Local Inner Classes, might be this will help you understand the situation in a much better way :-)

Related

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.

I have created a private class "PathakP" but I am getting PathakP cannot be resolved to a type

I tried to create a dialog box with Jbutton but when I am adding actionListener to it and passing the class to button which i have created to implements ActionListener I am getting "PathakP(Class Name) cannot be resolved to a type"
the code I have used is
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class GUI1 extends JFrame {
private JTextField J;
private Font pf,bf,itf,bif;
private JRadioButton pb,bb,ib,bib;
private ButtonGroup B;
private JButton ab;
public GUI1(){
super("To check the Font styles" );
setLayout(new FlowLayout());
J=new JTextField("This is the Text who's Font will be Changed pahtak is with me ",40);
add(J);
pb=new JRadioButton("Plain Button",true);
bb=new JRadioButton("Bold Button",false);
bib=new JRadioButton("Bold & Italic Button",false);
ib=new JRadioButton("Italic Button",false);
ab=new JButton("PathakButton");
add(ab);
add(pb);
add(bb);
add(bib);
add(ib);
B=new ButtonGroup();
B.add(pb);
B.add(bb);
B.add(bib);
B.add(ib);
pf=new Font("Serif",Font.PLAIN,15);
bf=new Font("Serif",Font.BOLD,15);
itf=new Font("Serif",Font.ITALIC,15);
bif=new Font("Serif",Font.BOLD+Font.ITALIC,16);
J.setFont(pf);
pb.addItemListener(new HandlerClass(pf));
bb.addItemListener(new HandlerClass(bf));
bib.addItemListener(new HandlerClass(bif));
ib.addItemListener(new HandlerClass(itf));
ab.addActionListener(new PathakP());
}
private class HandlerClass implements ItemListener{
private Font font;
public HandlerClass(Font f){
font=f;
}
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
J.setFont(font);
}
private class PathakP implements ActionListener{
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(null, "This is just JOptionPane example");
}
}
}
}
Main Class
import javax.swing.*;
public class Apples {
public static void main(String[] args) {
GUI1 G=new GUI1();
G.setVisible(true);
G.setSize(500,250);
G.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I don't believe there is any error in the main class
I can troubleshoot this error by just creating another class outside but I want to know why it is not taking the class I have created and show unused in it
Your PathakP is written inside of HandlerClass. You have two solutions from there (after having corrected your bracket problem)
Either write it inside of GUI instead and since you're calling it from the constructor, it will be binded to this instance of GUI
Or, if you want to keep it within HandlerClass, you need to bind it to an instance of HandlerClass : ab.addActionListener(new HandlerClass().new PathakP())

Java - Use of non final variables in anonymous inner class?

In a school test I used non final variables inside an anonyme inner class.
On the the school Computer and on my private Computer(using x86 jre1.8.0_45) it is working.
However, on the teachers Laptop Eclipse is showing errors (The variables should use final). He is using jre1.8.0.x version (don't know the exact version).
Any ideas why it is working on my computer and not on his computer?
In this code example the no final object jLabel is used inside the actionPerformed function of the ActionListener:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
public class Main {
public Main(String[] args) {
JLabel jLabel = new JLabel();
JButton button = new JButton();
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
jLabel.setText("xyz");
}
});
}
}
Newer java versions are more tolerant in this concern: they only require that they should be "effectively final".
At the end, the difference is not soo big - you only can use variables which you COULD tag with final; you may not modify them.
If you are at that place, you as well can make them "really" final, and it works everywhere.
BTW, on 1.8 with its new lambda syntax you can write more elegantly
button.addActionListener((ActionEvent arg0) -> jLabel.setText("xyz"));
You could define the Listener not as an anonymous class but as a private inner class in order to avoid that problem:
public class Main {
public Main(String[] args) {
JLabel jLabel = new JLabel();
JButton button = new JButton();
button.addActionListener(new MyActionListener(jLabel));
}
private class MyActionListener implements ActionListener {
private JLabel jLabel;
MyActionListener(JLabel jLabel) {
this.jLabel = jLabel;
}
#Override
public void actionPerformed(ActionEvent arg0) {
jLabel.setText("xyz");
}
}
}
This way you can just pass the label (and button if you need) to the constructor of the listener and will be able to use it without any problems.

How can I add the ActionEvent to the JButton so that when i click it it will fire the event?

I want to be able to add the ActionListener to the JButton but cannot seem to get it to work properly.
I have tried to add the ActionListeneer and also the ActionEvent and neither seems to fire the ActionPerformed method.
I did not one curious aspect was the the compiler made me take off the #Override keyword since the interface is used to create a variable and not implemented.
Does this make a difference? I am certain that you can do it this way but I think I am just a bit off the mark.
Code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class testInterfaces2 {
static ActionListener m;
static ActionEvent me;
testInterfaces2() {
}
public void actionPerformed(ActionEvent e) {
System.out.println("Mouse Clicked");
}
public static void main(String[] args) {
JFrame f = new JFrame("Test");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JButton pButton = new JButton("Print");
pButton.addActionListener(m);
//pButton.addActionListener(m.actionPerformed(me));
f.add("Center", pButton);
f.pack();
f.setVisible(true);
}
}
It should be like this and remove ActionListener and ActionEvent variables that is not needed.
public class testInterfaces2 implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Mouse Clicked");
}
...
JButton pButton = new JButton("Print");
pButton.addActionListener(this);
}
#Override doesn't do any thing extra other than compile time checking of the overridden method.
In simple term, You need a class that implements ActionListener and obviously implements actionPerformed() method. Simply create a object of that class and pass in addActionListener() method.
I did not one curious aspect was the the compiler made me take off the
#Override keyword since the interface is used to create a variable and
not implemented.
This should have highlighted your first problem, your testInterfaces2 class can't override actionPerformed as it's not defined in any part of the parent class or it's parents. This is because testInterfaces2 doesn't implement ActionListener directly or indirectly (via inheritance).
Your second problem is m is null, you've never initialised it
Take a closer look at How to write ActionListeners for more details
I think it's best to define a new ActionListener for each button. Like this
JButton pButton = new JButton();
pButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
System.exit(0);
}
});

Access Intellij Form Designer objects

When I design a Java Form with intellij it only declares private components like
Private JPanel myPanel;
But how can I access this object from within my class sourcefile. E.g. when I want to add a JButton to myPanel?
i know I can write a getter for myPanel but how do I access it then?
Let me explain my solution with the change of a button text.
Create the button in intellij GUI Designer
Add a getter method to it (go to source, write getter manually or let intellij do it for you)
Now you can use the getter method to access the objects methods.
Example: Change button text of a GUI-designer-created button on click:
import javax.swing.*;
import java.awt.event.*;
public class TestForm {
private JButton button1;
private JPanel panel1;
public TestForm() {
getButton1().addActionListener(new clickListener());
}
public JButton getButton1() {
return button1;
}
public static void main(String[] args) {
JFrame frame = new JFrame("TestForm");
frame.setContentPane(new TestForm().panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public void changeTextOnButton(){
getButton1().setText("gwerz");
}
public class clickListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (getButton1().getText().equals("Button")){
getButton1().setText("Dgsdg");
}
else {
getButton1().setText("Button");
}
}
}
}

Categories

Resources