简体   繁体   中英

Adding text to a label from another class - Simple Logic Issue

I have a label and a button in a class called FrameTest , when i press the button, a method named buttonpressed get's executed from the class Test . In this buttonpressed method i will set a text to the label found in the FrameTest class.

The problem i have is that, the text for the label is not getting set. The reason is that i am creating a separate object to call the buttonpressed method;

public void actionPerformed(ActionEvent arg0) {
                    Test t = new Test();
                    t.buttonpress();
                }

and i am creating a separate object in the main method of the Test class to create the UI.

public static void main(String[] args) {

         FrameTest f = new FrameTest();
         f.mainScreen();

    }

The full code as follows;

public class FrameTest extends JFrame {

private JPanel contentPane;
private JLabel lblLabel;
private FrameTest ft = this;

//private FrameTest frame;
/**
 * Launch the application.
 */
public  void mainScreen() {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                //FrameTest frame = new FrameTest();
                //setVisible(true);

                FrameTest frame = ft;
                frame.setVisible(true);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}


public void writeLabel(String k){
    this.lblLabel.setText(k);

}

public FrameTest() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setExtendedState(JFrame.MAXIMIZED_BOTH); 

    //setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    contentPane.setLayout(new BorderLayout(0, 0));
    setContentPane(contentPane);

    lblLabel = new JLabel("LABEL");
    contentPane.add(lblLabel, BorderLayout.CENTER);

    JButton btnNewButton = new JButton("Press");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            Test t = new Test();
            t.buttonpress();
        }
    });
    contentPane.add(btnNewButton, BorderLayout.WEST);
    //pack();
    setLocationByPlatform(true);
}

}

Test Class

public class Test {


public static void main(String[] args) {

     FrameTest f = new FrameTest();
     f.mainScreen();

}

public void buttonpress(){
     FrameTest f = new FrameTest();

     f.writeLabel("Button was pressed");

}

1) Dont extend JFrame class unnecessarily.

2) dont use setContentPane() unless thats what you want. Rather just simply JFrame#add(..) .

3) Steer away from EventQueue and use SwingUtilities block rather

4) Dont forget to call JFrame#pack(); before setting JFrame visible.

5) Java naming convention is CamelCase so buttonPress() is correct not buttonpress()

Here is an example I made (basically your code fixed):

Test.java: (This is the main class which will create an instance of your FrameTest and has the method to change JLabel text)

import javax.swing.SwingUtilities;

public class Test {

    private static FrameTest f;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                f = new FrameTest();
                f.mainScreen();
            }
        });
    }

    void buttonPress() {
        f.writeLabel("Hello");
    }
}

FrameTest.java: (This class will show the JFrame and create a new instance of class Test to call buttonPress() ):

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class FrameTest {

    private JPanel panel;
    private JLabel lblLabel;
    private JFrame frame;

    private void initComponents() {
        frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);

        panel = new JPanel();
        panel.setBorder(new EmptyBorder(5, 5, 5, 5));
        panel.setLayout(new BorderLayout(0, 0));

        lblLabel = new JLabel("LABEL");
        panel.add(lblLabel, BorderLayout.CENTER);

        JButton btnNewButton = new JButton("Press");
        btnNewButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Test t = new Test();
                t.buttonPress();
            }
        });

        panel.add(btnNewButton, BorderLayout.WEST);

        frame.add(panel);

        frame.setLocationByPlatform(true);
        frame.pack();
        frame.setVisible(true);
    }

    public void writeLabel(String k) {
        this.lblLabel.setText(k);
    }

    void mainScreen() {
        initComponents();
    }
}

Pass your FrameTest object to the buttonpress method and use it there, instead of creating a new object:

public void buttonpress(FrameTest f) {
     f.writeLabel("Button was pressed");    
}

Change the invocation of the method like so:

btnNewButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        Test t = new Test();
        t.buttonpress(FrameTest.this);
    }
});

You have to use FrameTest.this here, as you're inside of an anonymous class implementing ActionListener, so the normal this would reference to that anonymous class.

- Well the first approach is using Composition Principle, where you create an instance of FrameTest.java in Test.java class and then access the Label (use Getter Setters for this label in FrameTest) in FrameTest.java class using this instance.

- Second approach is a dirty and quick fix one, make the Label static in FrameTest.java class and directly set the value from Test.java class. Voila its done.....

- The reason your code is not working, cause you have created a very new instance of the FrameTest class . So now you either pass the FrameTest Object Reference Variable to buttonpress() method or make the label static .

Eg:

public class FrameTest extends JFrame {

private JPanel contentPane;
public static JLabel lblLabel;

.....

.....

}

Or

public void buttonpress(FrameTest f) {
     f.writeLabel("Button was pressed");    
}

/////////////////////////// Edited Part ///////////////////////////////////

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

class FrameTest extends JFrame {

    private JPanel contentPane;
    private JLabel lblLabel;
    private FrameTest ft = this;

    public void mainScreen() {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {

                    FrameTest frame = ft;
                    frame.setVisible(true);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void writeLabel(String k) {
        this.lblLabel.setText(k);

    }

    public FrameTest() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setExtendedState(JFrame.MAXIMIZED_BOTH);

        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        lblLabel = new JLabel("LABEL");
        contentPane.add(lblLabel, BorderLayout.CENTER);

        JButton btnNewButton = new JButton("Press");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Test t = new Test();

                t.buttonpress(FrameTest.this); // Passing the current object to
                                                // the Test class
                                                // You can use just "this" , but
                                                // as we are in an Anonymous
                                                // Inner Class here,
                                                // we have to use
                                                // "Class_name.this"

            }
        });
        contentPane.add(btnNewButton, BorderLayout.WEST);
        // pack();
        setLocationByPlatform(true);
    }

}

public class Test {

    public static void main(String[] args) {

        FrameTest f = new FrameTest();
        f.mainScreen();

    }

    public void buttonpress(FrameTest f) { // Receiving the reference to the
                                            // current frame, but remember
                                            // THOUGH IT SEEMS that we are passing the
                                            // reference but still in
                                            //  Here and in Java its always pass
                                            // by copy.( ie pass by value).

        f.writeLabel("Button was pressed");

    }
}

Just change your Test class like below

package com.test;

public class Test {

    private static FrameTest f;

    public static void main(String[] args) {

        f = new FrameTest();
        f.mainScreen();

    }

    public void buttonpress() {
        f.writeLabel("Button was pressed");
    }
}

The actual problem was

  1. You created a FrameTest variable f in main and shown the UI to user.
  2. Then on button press you again created another FrameTest instance f , which does not map the original/first f

Now i treat the variable as a class variable and it works as expected

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM