Unseen initialized objects in another class in Java - java

To be short, I create a class Something witch have a function with a JFrame where I have a label and a button on it. On the button I have an addActionListener(new changeLabel()).
I did class changeLabel in the src package for the listener but when I start the application and I click the button throw an NullPointerException on the changeLabel at
nameLabel.setText("Name changed");
line. I want to mention that if I create this listener class in Something class, work perfectly.
I don't know why throw null exception because the label is initialized firstly and after that, the button just want to change the text.
I tryed to make a getFunction, to call that label, I tryed with object Something, with object changeLabel etc... but doesn't work.
Here is some code
package trying;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.*;
public class Something {
JFrame frame;
JLabel changeName;
JButton button;
public void gui(){
frame = new JFrame();
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//is just an example
changeName = new JLabel("Stefan");
//is just an example
button = new JButton("Change");
button.addActionListener(new changeLabel());
frame.getContentPane().add(changeName, BorderLayout.NORTH);
frame.getContentPane().add(button, BorderLayout.SOUTH);
frame.setVisible(true);
}
public static void main(String args[]){
new Something().gui();
}
}
The listener class
package trying;
import java.awt.event.*;
public class changeLabel extends Something implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
changeName.setText("Andrei");
}
}
How can I solve this problem?

The problem is that because the changeLabel class extends Something, it will contain it's own changeName variable which is not initialized == null.
You can:
make the changeLabel implementation private class of Something (good practice) or
pass the JLabel to its constructor.
In both ways changeLabel should not extend Something.
Code Sample #1:
public class Something {
JFrame frame;
JLabel changeName;
JButton button;
public void gui(){
frame = new JFrame();
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//is just an example
changeName = new JLabel("Stefan");
//is just an example
frame.getContentPane().add(changeName, BorderLayout.NORTH);
button = new JButton("Change");
button.addActionListener(new changeLabel());
frame.getContentPane().add(button, BorderLayout.SOUTH);
frame.setVisible(true);
}
public static void main(String args[]){
new Something().gui();
}
class changeLabel implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
changeName.setText("Andrei");
}
}
}
Code Sample #2:
public class Something {
...
public void gui() {
...
button.addActionListener(new changeLabel(changeName));
}
}
public class changeLabel implements ActionListener {
private final JLabel label;
public changeLabel(JLabel label) {
this.label = label;
}
#Override
public void actionPerformed(ActionEvent e) {
label.setText("Andrei");
}
}

Related

Is there a way to reference setVisible() and dispose() from an ActionListener in a separate class file?

I'm working on a very complicated, multi-layered Swing GUI, and the main issue I'm running into right now involves having a JButton ActionListener perform setVisible() on a separate JFrame and immediately dispose() of the current JFrame. Because of the length of my code, it's important that main, both JFrames, and the ActionListener are all split into individual class files. I wrote a VERY simplified version of my problem, split into 4 tiny class files. Here they are:
File 1:
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame g1 = new GUI1();
g1.pack();
g1.setLocation(200,200);
g1.setVisible(true);
JFrame g2 = new GUI2();
g2.pack();
g2.setLocation(400,200);
g2.setVisible(false);
}
}
File 2:
import javax.swing.*;
public class GUI1 extends JFrame {
JPanel panel;
JButton button;
public GUI1() {
super("GUI1");
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
button = new JButton("Create GUI2");
button.addActionListener(new Listener());
add(panel);
add(button);
}
}
File 3:
import javax.swing.*;
public class GUI2 extends JFrame {
JPanel panel;
JLabel label;
public GUI2() {
super("GUI2");
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
label = new JLabel("I'm alive!");
add(panel);
add(label);
}
}
File 4:
import java.awt.event.*;
public class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
GUI2.setVisible(true);
GUI1.dispose();
}
}
As you can see, the only function of the ActionListener is to set GUI2 to visible and dispose of GUI1, but it runs the error "non-static method (setVisible(boolean) and dispose()) cannot be referenced from a static context". I figure this is because both methods are trying to reference objects that were created in main, which is static. My confusion is how to get around this, WITHOUT combining everything into one class.
Any suggestions? Thanks!
EDIT:
Here's the above code compiled into one file... although it returns the exact same error.
import javax.swing.*;
import java.awt.event.*;
public class Test {
public static void main(String[] args) {
JFrame g1 = new GUI1();
g1.pack();
g1.setLocation(200,200);
g1.setVisible(true);
JFrame g2 = new GUI2();
g2.pack();
g2.setLocation(400,200);
g2.setVisible(false);
}
}
class GUI1 extends JFrame {
JPanel panel;
JButton button;
public GUI1() {
super("GUI1");
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
button = new JButton("Create GUI2");
button.addActionListener(new Listener());
add(panel);
add(button);
}
}
class GUI2 extends JFrame {
JPanel panel;
JLabel label;
public GUI2() {
super("GUI2");
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
label = new JLabel("I'm alive!");
add(panel);
add(label);
}
}
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
GUI2.setVisible(true);
GUI1.dispose();
}
}
You have to pass instances of frame1 and frame2 to your ActionListener.
import java.awt.event.*;
public class Listener implements ActionListener {
private JFrame frame1, frame2;
public Listener(JFrame frame1, JFrame frame2) {
this.frame1 = frame1;
this.frame2 = frame2;
}
public void actionPerformed(ActionEvent e) {
frame2.setVisible(true);
frame1.dispose();
}
}
This means you have to pass an instance of frame2 to your GUI1 class.
import javax.swing.*;
public class GUI1 extends JFrame {
JPanel panel;
JButton button;
public GUI1(JFrame frame2) {
super("GUI1");
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
button = new JButton("Create GUI2");
button.addActionListener(new Listener(this, frame2));
add(panel);
add(button);
}
}
This means you have to create the frames in the reverse order.
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame g2 = new GUI2();
g2.pack();
g2.setLocation(400,200);
g2.setVisible(false);
JFrame g1 = new GUI1(g2);
g1.pack();
g1.setLocation(200,200);
g1.setVisible(true);
}
}

setContentPane() and addActionListener gets a NullPointerException

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Form1 {
private JPanel panel1;
private JButton button1;
public Form1() {
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked");
}
});
}
public static void main(String args[]){
JFrame frame = new JFrame("Form 1");
frame.setContentPane(new Form1().panel1);
frame.pack();
frame.setVisible(true);
}
}
The error relates to the setContentPane in main method and then also the actionListener. I've posted the exact error below. Why is this? I created this using the IntelliJ IDEA GUI form creator.
Exception in thread "main" java.lang.NullPointerException
at Form1.<init>(Form1.java:12)
at Form1.main(Form1.java:22)
In Java you can't use variables that are not initialized, else you will receive a NPE. See the following code and please read a Java book :)
public class Form1 {
private JPanel panel1;
private JButton button1;
public Form1() {
panel1 = new JPanel();
button1 = new JButton1("Press Me");
panel1.add(button1);
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked");
}
});
}
public static void main(String args[]){
JFrame frame = new JFrame("Form 1");
frame.setContentPane(new Form1().panel1);
frame.pack();
frame.setVisible(true);
}
}
So there are 2 issues that you're going to run into that are causing that error. After you create an object (JButton, JPanel in this case), you have to instantiate them. There are a lot of different ways to do this, and it depends on what you're trying to do, but the simplest fix for your issue here is to add the following lines in the constructor:
panel1 = new JPanel();
button1 = new JButton();
Your code should run fine after that.

How can I change the JPanel from another Class?

Hi, I'm new to Java and I have the following problem:
I created a JFrame and I want the JPanel to change when clicking a JButton. That does almost work.The only problem is that the program creates a new window and then there are two windows. One with the first JPanel and one with the second JPanel.
Here is my current code:
first class:
public class Program {
public static void main (String [] args) {
new window(new panel1());
}
}
second class:
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Window extends JFrame {
private static final long serialVersionUID = 1L;
Window(JPanel panel) {
setLocation((int) Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 200,
(int) Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 100);
setSize(400, 200);
setTitle("test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setContentPane(panel);
setVisible(true);
}
}
third class:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Panel1 extends JPanel {
private final long serialVersionUID = 1L;
Panel1() {
JButton nextPanelButton = new JButton("click here");
add(nextPanelButton);
ActionListener changePanel = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
new window(new panel2());
}
};
nextPanelButton.addActionListener(changePanel);
}
}
fourth class:
public class Panel2 extends JPanel {
private static final long serialVersionUID = 1L;
Panel2() {
JLabel text = new JLabel("You pressed the Button!");
add(text);
}
}
But I just want to change the JPanel without opening a new window. Is there a way to do that?
Thanks in advance!
This is a demo
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MainFrame("Title").setVisible(true);
});
}
}
MainFrame.java
import javax.swing.*;
import java.awt.*;
public class MainFrame extends JFrame {
private JPanel viewPanel;
public MainFrame(String title) {
super(title);
createGUI();
}
private void createGUI() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
setMinimumSize(new Dimension(600, 480));
viewPanel = new JPanel(new BorderLayout());
add(viewPanel, BorderLayout.CENTER);
showView(new View1(this));
pack();
}
public void showView(JPanel panel) {
viewPanel.removeAll();
viewPanel.add(panel, BorderLayout.CENTER);
viewPanel.revalidate();
viewPanel.repaint();
}
}
View1.java
import javax.swing.*;
import java.awt.*;
public class View1 extends JPanel {
final private MainFrame owner;
public View1(MainFrame owner) {
super();
this.owner = owner;
createGUI();
}
private void createGUI() {
setLayout(new FlowLayout());
add(new JLabel("View 1"));
JButton button = new JButton("Show View 2");
button.addActionListener(event -> {
SwingUtilities.invokeLater(() -> owner.showView(new View2(owner)));
});
add(button);
}
}
View2.java
import javax.swing.*;
import java.awt.*;
public class View2 extends JPanel {
final private MainFrame owner;
public View2(MainFrame owner) {
super();
this.owner = owner;
createGUI();
}
private void createGUI() {
setLayout(new FlowLayout());
add(new JLabel("View 2"));
JButton button = new JButton("Show View 1");
button.addActionListener(event -> {
SwingUtilities.invokeLater(() -> owner.showView(new View1(owner)));
});
add(button);
}
}
First of all, take a look at Java naming conventions, in particular your class names should start with a capitalized letter.
If you want to avoid to open a new window every time you click the button, you could pass your frame object to Panel1 constructor, and setting a new Panel2 instance as the frame content pane when you click the button. There is also no need to pass Panel1 to Window constructor (please note that Window class is already defined in java.awt package, it would be better to avoid a possible name clash renaming your class ApplicationWindow, MyWindow or something else).
You could change your code like this (only relevant parts):
public class Program
{
public static void main (String [] args) {
SwingUtilities.invokeLater (new Runnable () {
#Override public void run () {
new Window ().setVisible (true);
}
};
}
}
class Window extends JFrame
{
// ...
Window () {
// ...
setContentPane(new Panel1 (this));
}
}
class Panel1 extends JPanel
{
// ...
Panel1 (JFrame parent) {
// ...
ActionListener changePanel = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
parent.setContentPane (new Panel2 ());
}
};
// ...
}
Also note the SwingUtilities's invokeLater call, which is the best way to initialise your GUI in the EDT context (for more info look at this question).
Finally, you could avoid to create a new Panel2 instance every time you click the button, simply by using a CardLayout.
Take a look at the official tutorial.
This is an old post, but it may be useful to answer it in a simplified way. Thanks to mr mcwolf for the first answer.
If we want to make 1 child jframe interact with a main jframe in order to modify its content, let's consider the following case.
parent.java and child.java.
So, in parent.java, we have something like this:
Parent.java
public class Parent extends JFrame implements ActionListener{
//attributes
//here is the class we want to modify
private some_class_to_modify = new some_class_to_modify();
//here is a container which contains the class to modify
private JPanel container = new JPanel();
private some_class = new some_class();
private int select;
//....etc..etc
//constructor
public Parent(){
this.setTitle("My title");
//etc etc
//etc....etc
container.add(some_class_to_modify,borderLayout.CENTER);
}
//I use for instance actionlisteners on buttons to trigger the new JFrame
public void actionPerformed(ActionEvent arg0){
if((arg0.getSource() == source_button_here)){
//Here we call the child class and send the parent's attributes with "this"
Child child = new Child(this);
}
//... all other cases
}//Here is the class where we want to be able to modify our JFrame. Here ist a JPanel (Setcolor)
public void child_action_on_parent(int selection){
this.select = selection;
System.out.println("Selection is: "+cir_select);
if(select == 0) {
//Do $omething with our class to modify
some_class_to_modify.setcolor(Color.yellow);
}
}
In child.java we would have something like this:
public class Child extends JFrame implements ActionListener {
//Again some attributes here
private blabla;
//Import Parent JFrame class
private Parent owner;
private int select_obj=0;
//Constructor here and via Parent Object Import
public Child(Parent owner){
/*By calling the super() method in the constructor method, we call the parent's
constructor method and gets access to the parent's properties and methods:*/
super();
this.owner = owner;
this.setTitle("Select Method");
this.setSize(400, 400);
this.setContentPane(container);
this.setVisible(true);
}
class OK_Button implements ActionListener {
public void actionPerformed(ActionEvent e) {
Object Selection = select;
if(Selection == something) {
select_obj=0;
valid = JOptionPane.showConfirmDialog(null,"You have chosen option 1. Do you want to continue?","Minimum diameter",2);
}
System.out.println("Option is:"+valid);
if(valid == 0) {
setVisible(false);
//Here we can use our herited object to call the child_action_on_parent public class of the Parent JFrame. So it can modify directly the Panel
owner.child_action_on_parent(select_obj);
}
}
}

Java Actionlistener on Button

import java.awt.*;
public class TestButton {
private Frame f;
protected Button b;
public TestButton() {
f = new Frame("Test");
b = new Button("Press Me!");
b.setActionCommand("ButtonPressed");
}
public void launchFrame() {
b.addActionListener(new ButtonHandler());
f.add(b, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
public static void main(String args[]) {
TestButton guiApp = new TestButton();
guiApp.launchFrame();
}
}
import java.awt.*;
import java.awt.event.*;
public class ButtonHandler extends TestButton implements ActionListener {
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if(source==b)
{
System.out.println("Action occurred");
System.out.println("Button's command is: "
+ e.getActionCommand());
}
}
}
I'm trying to invoke a ActionEvent when the button b is pressed but not working with getSource.
You're misusing inheritance. The ButtonHandler class should not extend the TestButton class, since the b variable in the handler class refers to a completely different Button object from the one displayed. I suggest:
Use the Swing library, not the AWT library
You can get the JButton pressed from the ActionEvent's getSource() method and use it directly.
If you need a reference to the GUI in the handler, pass in a reference in the handler's constructor.
Don't misuse inheritance to solve problems that don't involve inheritance issues.
For example:
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestButton extends JPanel {
private JButton btn = new JButton(new ButtonAction("Press Me!", "ButtonPressed"));
public TestButton() {
add(btn);
}
private static void createAndShowGUI() {
TestButton testButton = new TestButton();
JFrame frame = new JFrame("TestButton");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testButton );
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
#SuppressWarnings("serial")
class ButtonAction extends AbstractAction {
public ButtonAction(String name, String actionCommand) {
super(name);
putValue(ACTION_COMMAND_KEY, actionCommand);
}
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Button's actionCommand is: " + evt.getActionCommand());
}
}
That happens because you extends TestButton in your ButtonHandler, because of you have 2 different instances of your Button and thea are not equals.
To fix that you can remove extends TestButton and make ButtonHandler as inner class of TestButton
or you can compare action commands instead of Button's like next:
if(((Button)source).getActionCommand().equals("ButtonPressed"))
I think you need to remove extends TestButton as the 2 different instances of the buttons are not equal. You should go for a ButtonHandler as inner class or anonymous class to implement this.
Check this question:
Java Button Handler

Sending Jframe Jtextfield to another class

I have a JFrame that has a textfield and a button. It should become visible at the start of program and when I click on the button, It should become invisible and send the text of textfield to another class. but It send nothing and when I click on the button the IDE goes to the debug mode.
public class JframeFoo extends JFrame {
private String username = new String();
public JframeFoo() {
// --------------------------------------------------------------
// Making Frame for login
final JTextField usernameFiled = new JTextField();
this.add(usernameFiled);
JButton signinButton = new JButton();
// ------------------------------------------------------------
signinButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
username = usernameFiled.getText();
setVisible(false);
Main.mainpage.setVisible(true);
}
});
// --------------------------------------------------------------------------
}
public String getuserName() {
return this.username;
}
}
my another class calls Jframe:
System.out.println(JframeFoo.getusername);
Ignoring for a moment that having multiple JFrames jumping out at the user is not a great user interface design, for one object to communicate with another object, it must have a valid reference to the other object. (sorry interrupted by daughter).
So for one JFrame class to get information from the other, it must have a reference to the first object that gets the text, and I don't see you passing that reference, such as in a constructor or setter method.
So for instance if an object of Class1 has information that an object of Class2 needs, then one way to pass it is to give Class2 a reference to the valid instance of Class1, and then have Class2 get the information from the Class1 instance. e.g.,
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class ClassMain {
private static void createAndShowGui() {
ClassMain mainPanel = new ClassMain();
JFrame frame = new Class1();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Class1 extends JFrame {
private JTextField textfield = new JTextField(10);
public Class1() {
JPanel contentPane = (JPanel) getContentPane();
contentPane.setLayout(new FlowLayout());
add(textfield);
add(new JButton(new AbstractAction("Open Window") {
#Override
public void actionPerformed(ActionEvent arg0) {
Class2 class2 = new Class2(Class1.this);
Class1.this.setVisible(false);
class2.pack();
class2.setVisible(true);
class2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}));
}
public String getTextfieldText() {
return textfield.getText();
}
}
class Class2 extends JFrame {
private Class1 class1;
private JLabel label = new JLabel("");
public Class2(Class1 class1) {
this.class1 = class1;
label.setText(class1.getTextfieldText());
add(label);
}
}

Categories