How to change a JLabel with a button from another class? - java

I have two classes and a text file database, The JLabel in the first class, let's call it class1 automatically set it self to the number in the database. Now, in class2 I have this little JFrame and a text field and of course a button, the value I put in the text field overwrites the one in the database, but here's the problem. The label in the first class wont update while running, but if I restart it it will show me the value that I want.
How do I update it while the program is running?
I've tried to change the label in the buttonActionperformed in the other class but it gives me a NullPointException every time.
How do I fix this?
THE MAIN CLASS ( JUST THE JFRAME )
package BankrollG;
import java.awt.Graphics;
import javax.swing.JFrame;
public class BGbrain {
BGbody body = new BGbody();
JFrame Frame = new JFrame();
public BGbrain() {
Frame.setSize(body.width, body.height);
Frame.setTitle(body.title);
Frame.setResizable(false);
Frame.setDefaultCloseOperation(Frame.EXIT_ON_CLOSE);
Frame.add(body.panel);
Frame.setLocationRelativeTo(null);
Frame.setFocusable(true);
Frame.setVisible(true);
}
public static void main(String[] args ) {
new BGbrain();
}
}
Then you got the class with the components:
private JLabel bankroll_label
public BGbody(){
panel.setLayout(null);
windowComponents();
}
public void windowComponents() {
// Bankroll database access
try {
FileReader fr = new FileReader("Bankroll.txt");
BufferedReader br = new BufferedReader(fr);
set_bankroll = br.readLine();
} catch(IOException e) {
System.out.println("FEL MED LĂ„SNING AV DATABAS /// BGBODY");
}
}
}
THEN you got the JFrame class that I created with the netbeans function
private void AddcurrencyActionPerformed(java.awt.event.ActionEvent evt) {
String CBR = txt_bankroll.getText();
try {
FileWriter fw = new FileWriter("Bankroll.txt");
PrintWriter pw = new PrintWriter(fw);
pw.println(CBR);
pw.close();
} catch(IOException e) {
System.out.println("FEL MED INSKRIVNINGEN I DATABASEN");
}
}
Now, everything goes as plan, but I can't update my JLabel "bankroll_label" from the button class because it just returns nullpointsexceptions. The data is there, because the JLabel reads from the database but it wont update when changes has been made from the button class. So a getter setter method wont work because the value IS there but it wont update the JLabel.
I hope this made it easier to understand my problem.
It's ALOT more code, that dont have to do with this, I hope I simplified it at least some.

Your question is a specific example of a basic problem in programming in Java -- how to transfer information between classes. There are several ways to do this, one of the most elegant being giving to use a "model" class that holds your program's logic code and key data, having one class change the model's state by changing a text String that it holds. Then using a listener or observer pattern, have the model notify the other class that it has been changed so the other class can extract the new information, its new String from the model. While this is likely the best solution, it may be a bit of overkill and likely is above your current level of coding, so for you, I'm not going to recommend this.
Instead, I'm going to recommend a simpler less elegant solution, that you instead have one class call a setter method of the other to push the new String into it.
One problem we have as volunteer answerers here is that your question is hard to answer because it lacks critical code, making it hard for us to guess why your code is misbehaving, why specifically you're running into a NullPointerException (or NPE) when you try to run it. So all I can do is guess, but guess I will try nevertheless.
For simplicity's sake, let's call one class the, the one that holds the JLabel, the LabelClass and the other class the ButtonTextFieldClass.
One possible reason is that you've got a NullPointerException is because your ButtonTextFieldClass may have a LabelClass variable, but never initialized the variable, something like so:
// this guy is null because it is never initialized
private LabelClass labelClass;
A simple solution could be to try to initialize it like so:
private LabelClass labelClass = new LabelClass();
But this won't work because while it does create and assign a LabelClass instance, it's likely not the LabelClass instance that is visualized in the running GUI.
A better solution is to give the ButtonTextFieldClass a setter method that allows other classes to set the ButtonTextFieldClass with the proper LabelClass instance.
e.g.,
public void setLabelClass(LabelClass labelClass) {
this.labelClass = labelClass;
}
This way the code that sets up both classes can pass the visualized LabelClass to the first class, and it can call methods on it.
A simple example of LabelClass could look like so:
class LabelClass extends JPanel {
private JLabel label = new JLabel("");
public LabelClass() {
setBorder(BorderFactory.createTitledBorder("Label Panel"));
add(label);
}
public void setLabelText(String text) {
label.setText(text);
}
}
I have it extend JPanel because this way it gives me the freedom of placing it into a JFrame or JDialog or other JPanel as I see fit. Note that I've made the JLabel private and have given the class a public setter method, setLabelText(String text), that allows outside classes the ability to set the JLabel's text.
The ButtonTextFieldClass could look something like:
class ButtonTextFieldClass extends JPanel {
private JTextField textField = new JTextField(10);
private JButton button = new JButton(new ButtonAction("Send Text"));
private LabelClass labelClass;
public ButtonTextFieldClass() {
setBorder(BorderFactory.createTitledBorder("Button TextField Panel"));
add(textField);
add(button);
}
// here we allow other classes to set instances of our LabelClass
public void setLabelClass(LabelClass labelClass) {
this.labelClass = labelClass;
}
// ....
I've also given the button an AbstractAction in place of an ActionListener since it is like a super ActionListener on steroids. Inside of it, I'd get the text from the JTextField and then call the LabelClass's setter method (if the variable is not null) to set the label's text:
public void actionPerformed(ActionEvent e) {
String text = textField.getText();
if (labelClass != null) {
labelClass.setLabelText(text);
}
}
Then to set everything up, in another class I'd create instances of both LabelClass and ButtonTextFieldClass, and then "hook them up" by calling the setter method:
LabelClass labelClass = new LabelClass();
ButtonTextFieldClass buttonTextFieldClass = new ButtonTextFieldClass();
buttonTextFieldClass.setLabelClass(labelClass); // set our reference
The whole thing could look like so:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class TransferData {
private static void createAndShowGui() {
LabelClass labelClass = new LabelClass();
ButtonTextFieldClass buttonTextFieldClass = new ButtonTextFieldClass();
buttonTextFieldClass.setLabelClass(labelClass); // set our reference
JPanel mainPanel = new JPanel(new GridLayout(0, 1));
mainPanel.add(buttonTextFieldClass);
mainPanel.add(labelClass);
JFrame frame = new JFrame("TransferData");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class LabelClass extends JPanel {
private JLabel label = new JLabel("");
public LabelClass() {
setBorder(BorderFactory.createTitledBorder("Label Panel"));
add(label);
}
public void setLabelText(String text) {
label.setText(text);
}
}
class ButtonTextFieldClass extends JPanel {
private JTextField textField = new JTextField(10);
private JButton button = new JButton(new ButtonAction("Send Text"));
// one possible solution -- give this class a variable
// of the LabelClass -- but don't initialize the variable
// here, but rather do it in a setter
private LabelClass labelClass;
public ButtonTextFieldClass() {
setBorder(BorderFactory.createTitledBorder("Button TextField Panel"));
add(textField);
add(button);
}
// here we allow other classes to set instances of our LabelClass
public void setLabelClass(LabelClass labelClass) {
this.labelClass = labelClass;
}
// an AbstractAction is like a "super" ActionListener
private class ButtonAction extends AbstractAction {
public ButtonAction(String name) {
super(name); // set the button's text and actionCommand
int mnemonic = (int) name.charAt(0); // get first char
putValue(MNEMONIC_KEY, mnemonic); // set mnemonic
}
#Override
public void actionPerformed(ActionEvent e) {
String text = textField.getText();
if (labelClass != null) {
labelClass.setLabelText(text);
}
}
}
}
For simplicity's sake, I've displayed both JPanels within the same GUI, but it could work just as well if one JPanel were in one JFrame and the other within a JDialog.

Related

JButton's actionPerformed doesn't change JTextField's text by using .setText() method

I have this code... in it it has a problem as in title: JTextField's text doesn't change when clicking the button. I don't know what the problem is, but I think actionPerformed is executed as the message dialog appears. I tried to use a constructor (of class Start) (instead of function "doIt") but it doesn't work either.
import javax.swing.*;
import java.awt.FlowLayout;
import java.awt.*;
import java.awt.event.*;
public class PalTransfer
{
public static void main(String[] args)
{
Starter starter = new Starter();
starter.doIt();
}
}
class Starter
{
JFrame PTMainFrame = new JFrame("In/Out - arch - access, ...");
JTextField TextFieldOfIP = new JTextField(20);
//String string = "I AM START OF STARTER";
void doIt()
{
PTMainFrame.setSize(900, 400); // Set the frame size
PTMainFrame.setLocationRelativeTo(null);
PTMainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField TextFieldOfIP = new JTextField(20);
JButton jBtn = new JButton("I AM A BUTTON!");
PTMainFrame.add(jBtn);
PTMainFrame.add(TextFieldOfIP);
FlowLayout layoutManager = new FlowLayout(0,10,5);
PTMainFrame.setLayout(layoutManager);
TextFieldOfIP.setText("I am doIt() method!"); //+++++++++++++++++++++++++++
jBtn.addActionListener(new ButtonListener());
PTMainFrame.setVisible(true); // to do // put later
}
class ButtonListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(null, "hello?");
TextFieldOfIP.setText("I am actionPerformed of JButton!");
}
}
}
Why have you defined this twice.
JTextField TextFieldOfIP = new JTextField(20);
Remove it from the DoIt() method it will work.
You have your class attribute TextFieldOfIP that your ButtonListeners is doing the setText on. But additional you have a local variable called TextFieldOfIP in your doIt() method. And thats the object you are placing on your JFrame.
Remove this redefinition line: JTextField TextFieldOfIP = new JTextField(20); of your doIt() method. Then you are placing the same object on your JFrame that your ButtonListener is doing the setText on and everything will work as expected.

JTextField.setText() does not work in method as an array

new Java programmer here so I might have a basic question here. I am making an array of JTextFields. I want to use setText outside of the class in a public method but it does not work. However, I am able to use setText in the class (not in a method). I am not sure why. Here is some code as a SSCCE to show what I am experiencing.
import java.awt.BorderLayout;
import javax.swing.*;
public class testSetText extends JFrame
{
private JPanel panel;
private JTextField[] arrayField;
private JTextField singleField;
public testSetText()
{
// Specify an action for close button
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Make a panel
panel = new JPanel();
// Make array of JTextField components
JTextField[] arrayField = new JTextField[2];
for (int i = 0; i < 2; i++)
{
arrayField[i] = new JTextField(10);
arrayField[i].setEditable(false);
arrayField[i].setText("<>!");
panel.add(arrayField[i]);
}
// Make just one JTextField component
singleField = new JTextField(10);
singleField.setText("Works here");
panel.add(singleField);
// Add to panel to frame
add(panel);
// Pack the contents of the window and display it
pack();
setVisible(true);
// This will work!
arrayField[0].setText("Array index in class");
// This won't? Why?
setInMethodWithArray();
// Is this a problem with JTextField itself? Let me try a single element
setInMethodWithSingleElement();
// Hmmm so an element in an array of JTextFields can be addressed with setText in a class but not
// in a method in same class with same statement. But a single JTextField can be used in a method
// by that same class. Why do arrays behave so differently?
// EDIT: So I misunderstood, it does not work with a non array as well either!!
}
public void setInMethodWithArray()
{
arrayField[1].setText("This text will never show up");
}
public void setInMethodWithSingleElement()
{
//singleField.setText("Works here as non-array"); <--- before edit
singleField.setText("nevermind, it does not work here either");
}
public static void main(String[] args)
{
new testSetText();
}
}
you should declare arrayField[] in class area so array Field is accessible from setInMethodWithArray() method.
JTextField[] arrayField = new JTextField[2]; //class area
in constructor initial it
arrayField[i]= new JTextField(10);
arrayField[i].setEditable(false);
yes this is work
arrayField[0].setText("Array index in class");
because arrayField in the constructor scope ..and you are accessing arrayField Within constructor .so it works..
This won't? Why?
setInMethodWithArray();
because method setInMethodWithArray() can't access arrayField[] because it's not in method scope or in class scope.that's because you have declare it in the constructor so after constructor code block execute arrayField doesn't exist .it's reference lost because it's local variable ..
public void setInMethodWithArray()
{
arrayField[1].setText("This text will never show up");
}
now set can access arratField[] so now your code will work
import java.awt.BorderLayout;
import javax.swing.*;
public class testSetText extends JFrame
{
private JPanel panel;
private JTextField singleField;
// Make array of JTextField components
private JTextField[] arrayField = new JTextField[2];
public testSetText()
{
// Specify an action for close button
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Make a panel
panel = new JPanel();
for (int i = 0; i < 2; i++)
{
arrayField[i] = new JTextField(10);
arrayField[i].setEditable(false);
arrayField[i].setText("<>!");
panel.add(arrayField[i]);
}
// Make just one JTextField component
singleField = new JTextField(10);
singleField.setText("Works here");
panel.add(singleField);
// Add to panel to frame
add(panel);
// Pack the contents of the window and display it
pack();
setVisible(true);
// This will work!
arrayField[0].setText("Array index in class");
// This won't? Why?
setInMethodWithArray();
// Is this a problem with JTextField itself? Let me try a single element
setInMethodWithArray();
// Hmmm so an element in an array of JTextFields can be addressed with setText in a class but not
// in a method in same class with same statement. But a single JTextField can be used in a method
// by that same class. Why do arrays behave so differently?
}
public void setInMethodWithArray()
{
arrayField[1].setText("This text will never show up");
}
public void setInMethodWithSingleElement()
{
singleField.setText("Works here as non-array");
}
public static void main(String[] args)
{
new testSetText();
}
}
output>>

using listeners with both list and button

Very new to Java, but I am slowly picking my way through things. So please be kind. I understand most things I've tried so far, and built a version of the following that uses console output, but now I'm trying to make a GUI. I tried the netbeans GUI maker, but it created so much new code that when I tried to pick through it, I got lost. I'm much better at learning by piecing new things together myself, not having an IDE generate a ton of code and then attempt to find where I want to work.
I am trying to build an window that has a list with three choices on the left side, a button in the middle that confirms your choice, and an answer output on the right. Once the button is pressed, the input from the list is read and is converted into a corresponding answer. As of right now, all I get is "We recommend... null" after selecting an option in the list. The button appears to do nothing at the moment.
I have used tutorials, hacked up others' code from online, and referenced a few books, but I'm stuck.
Here is what I have:
package diffguidegui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class DiffGuideGUI extends JPanel implements ListSelectionListener {
private JList resultsTabList;
private DefaultListModel listModel;
private static final String recommendString = "Recommend a Option";
private JButton recommendButton;
private String recommendOutput;
final JLabel output = new JLabel("We recommend..." + recommendOutput);
//build list
public DiffGuideGUI () {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("A");
listModel.addElement("B");
//create the list and put it in the scroll pane
resultsTabList = new JList(listModel);
resultsTabList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
resultsTabList.setSelectedIndex(0);
//listener for user input
resultsTabList.addListSelectionListener(this);
resultsTabList.setVisibleRowCount(2);
JScrollPane listScrollPane = new JScrollPane(resultsTabList);
//build the button at the bottom to fire overall behavior
recommendButton = new JButton(recommendString);
recommendButton.setActionCommand(recommendString);
recommendButton.addActionListener(new RecommendListener());
//create a panel that uses Boxlayout for the button
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.add(recommendButton);
//create a panel that uses Boxlayout for the label
JPanel outputPane = new JPanel();
outputPane.setLayout(new BoxLayout(outputPane, BoxLayout.LINE_AXIS));
outputPane.add(output);
add(listScrollPane, BorderLayout.WEST);
add(buttonPane, BorderLayout.CENTER);
add(outputPane, BorderLayout.EAST);
}
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
}
}
public void valueChanged(ListSelectionEvent e) {
if(e.getValueIsAdjusting() == false) {
if(resultsTabList.getSelectedIndex() == -1) {
recommendButton.setEnabled(false);
} else {
recommendButton.setEnabled(true);
}
}
}
//Create GUI and show it
private static void createAndShowGUI() {
JFrame frame = new JFrame("Recommend Window");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create and set up content pane
JComponent newContentPane = new DiffGuideGUI();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//display the window
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The button appears to do nothing at the moment.
It does something. It calculates the value for your recommendOutput varable. But you never output this value.
try the following:
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
System.out.println(recommendOutput); // <-###################
}
}
This should print the value to stdout
To put the value into your label try this instead:
output.setText(recommendOutput);
where do you set the text for the JLabel? It says "We recommend NULL" because recommenedOutput is null when the object is created. I dont see
output.setText("We recommend "+value) anywhere. You probably need output.invalidate() also. Try putting setText(String text)/invalidate() in the RecommendListener.actionPerformed() method.
output.setText("We recommend A");
output.invalidate();

How to refresh instance of class if some action in another class was done

I have class DnyMesice what creates many instances of JButton. Every instance contains variable poznamkaDne. This class DnyMesice contains actionListener to find poznamkaDne value of pushed JButton.
I have class Gui what creates one instance of mentioned class DnyMesice and one instance of JTextArea.
How can I refresh value of JTextArea (names poznamkovePole) if some JButton (in class DnyMesice) is pushed?
public class DnyMesice extends JPanel {
public String poznamkaDne="first note";
jButton tlacitkoDen;
public void zobrazMesic(Calendar kalendar){
for (c=1; c<30; c++){
tlacitkoDen = new JButton(Integer.toString(denvMesici));
tlacitkoDen.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
poznamkaDne="New note";
};
});
add(tlacitkoDen);
}
}
}
public class Gui extends JFrame {
...
public void zobrazKalendar(){
...
panel3 = new JPanel();
panel3.setLayout(new FlowLayout());
add(panel3);
JTextArea poznamkovePole;
poznamkovePole = new JTextArea();
poznamkovePole.setColumns(30);
poznamkovePole.setRows(5);
poznamkovePole.setText(panel2.poznamkaDne);
panel3.add(poznamkovePole);
}
Now the program shows in JTextArea only "first note" (which is defined during creating of instance JButton) but hot to refresh it after ActionListener action?
Maybe better if you will use:
Add to DnyMesice JTextArea link and in ActionListener change text.
public class DnyMesice extends JPanel {
private JTextArea poznamkaDne;
jButton tlacitkoDen;
public DnyMesice (JTextArea jTextArea){
this.poznamkaDne = jTextArea;
}
public void zobrazMesic(Calendar kalendar){
for (c=1; c<30; c++){
tlacitkoDen = new JButton(Integer.toString(denvMesici));
tlacitkoDen.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
poznamkaDne.setText("New note");
};
});
add(tlacitkoDen);
}
}
}
P.S. - And please don't forget to use Code Conventions for the Java
Modify as follows:
// add these methods
public void setPoznamkaDne(String s) {
poznamkaDne = s;
}
public String getPoznamkaDne() {
return poznamkaDne;
}
// CHANGE this method (KEEP the rest of the code!)
public void actionPerformed(ActionEvent evt) {
setPoznamkaDne("New note");
};
poznamkovePole.setText(panel2.getPoznamkaDne());
These changes should allow you to update the text. BUT you need to either call poznamekovePole.setText() somehow, or implement an advanced listener class. I recommend combining your class like #Too Strong Magic said, above.

How to make a JList "refresh" method in a JPanel class

I'm a beginner at java and want to make a JFrame with tabs containing a seperate JPanel. One panel has a list where it displays things that you select in a different panel, so I want this panel to always display a list of stuff that you have selected in a different panel (I hope that makes sense). To do this, I need to make a method to refresh the JList. This is the Farthest that I've gotten on that:
public class PanelClass extends JPanel {
private JList list;
private DefaultListModel listModel = new DefaultListModel();
private ArrayList<SomeOtherClass> objectArray = new ArrayList<SomeOtherClass>();
public PanelClass() {
list.setModel(listModel);
}
public void refresh() {
updateListModel();
list.setModel(listModel);
}
public void updateListModel() {
if (objectArray.isEmpty()) {
System.out.println("No Objects In Array!");
} else {
listModel.clear();
for (SomeOtherClass SOC : objectArray) {
// SOC.getName() just returns a string
listModel.addElement(SOC.getName());
}
}
}
public void addObjectToArray(SomeOtherClass SOC) {
objectArray.add(SOC);
}
}
Could someone please tell me how to make a "refresh" method to constantly keep the JList up to date?
The AWT/Swing event model is based upon the widgets being event sources (in the MVC paradigm, they are both view and controller). Different widgets source different event types.
Look at the java.awt.event (primarily), and javax.swing.event packages for the listener interfaces you'll need to implement and register in order to produce your desired effect.
Basically, you write a Listener implementation, and register it with Widget1. When Widget1 detects an event, it will notify you, and you can then use the information it provides to update Widget2.
For instance, if a button being clicked would add an object to your list, you might have something like below (I usually put this code in the encompassing JFrame class, and make it implement the listener interfaces; but you can choose to use inner classes or separate listener classes):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame implements ActionListener {
private JButton button = new JButton("Click me!");
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private JList<String> list = new JList<String>(listModel);
private int counter = 1;
public MyFrame() {
setTitle("Test Updates");
JTabbedPane tabs = new JTabbedPane();
add(tabs, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(list);
tabs.add("Selections", panel);
panel = new JPanel();
button.addActionListener(this);
panel.add(button);
tabs.add("Options", panel);
pack();
}
#Override
public void actionPerformed(final ActionEvent event) {
if (button.equals(event.getSource())) {
listModel.addElement("Item " + counter++);
}
}
/* Test it! */
public static void main(String[] args) {
final MyFrame frame = new MyFrame();
frame.addWindowListener(new WindowAdapter() {
#Override public void windowClosing(final WindowEvent e) {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}
This code sample is minimal, but it should give you an idea of how to go about implementing what you want.
You can do it in two way. First : Write it in infinite thread loop so that it will constantly update JList. Second : You can call refresh() method whenever new SOC objects are added in your ArrayList. It means you can call refresh() method from addObjectToArray() method which ultimately call the refresh method only when you have some change in your ArrayList.
FYI : I did it in my project and I went for second option.

Categories