2

Recently I've been trying to make a program that takes in a double in the form of a string. It then parses that to a double which goes to another class to be divided to a quarter or a half and then returns that output to a label.

I've been having an issue where when I click a button to actually submit what is inside the text field, the label doesn't change.

I've tried a lot of trial and error and I know I can change the text after doing new JLabel("test") for example. However, there seems to be an issue with my action listener for when the button is pushed. I can't tell if it's not seeing the button as being pushed.

NOTE: I am new to awt event things and swing as a whole, I usually operate just using the output terminal of visual studio code where it's just text and no graphics.

import javax.swing.*;
import java.awt.event.*;
import java.awt.Font;
import java.awt.Dimension;

public class MoneySorterRunner {
    
    private  MoneySorter sorter = new MoneySorter();

    private String input = "0";
    private double money = Double.parseDouble(input);
    private static JTextField typeHere = new JTextField();


///labels num1-3 are the labels being changed
    private static JLabel num1 = new JLabel(new MoneySorterRunner().sorter.divQuarter(new MoneySorterRunner().money));
    private static JLabel num2 = new JLabel(new MoneySorterRunner().sorter.divQuarter(new MoneySorterRunner().money));
    private static JLabel num3 = new JLabel(new MoneySorterRunner().sorter.divHalf(new MoneySorterRunner().money));

    public static void main(String args[]) {
        JFrame frame = new JFrame("Money Calculator - v0.1a");
        JPanel panel = new JPanel();
        JButton doThing = new JButton("Do a Thing");
        doThing.setActionCommand("Do a Thing");
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 250);
        frame.setLocation(200, 200);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        panel.setLayout(null);
        frame.setVisible(true);
        JLabel item1 = new JLabel("test");
        JLabel item2 = new JLabel("test");
        JLabel item3 = new JLabel("test");
        item1.setFont(new Font("Arial", Font.PLAIN, 30));
        item2.setFont(new Font("Arial", Font.PLAIN, 30));
        item3.setFont(new Font("Arial", Font.PLAIN, 30));
        num1.setFont(new Font("Arial", Font.PLAIN, 25));
        num2.setFont(new Font("Arial", Font.PLAIN, 25));
        num3.setFont(new Font("Arial", Font.PLAIN, 25));
        Dimension size1 = item1.getPreferredSize();
        Dimension size2 = item2.getPreferredSize();
        Dimension size3 = item3.getPreferredSize();
        panel.add(item1);
        panel.add(item2);
        panel.add(item3);
        panel.add(num1);
        panel.add(num2);
        panel.add(num3);
        panel.add(doThing);
        panel.add(typeHere);
        item1.setBounds(10, 10, size1.width + 3, size1.height);
        item2.setBounds(190, 10, size2.width + 3, size2.height);
        item3.setBounds(325, 10, size3.width + 3, size3.height);
        num1.setBounds(50, 50, 50, 25);
        num2.setBounds(200, 50, 50, 25);
        num3.setBounds(350, 50, 50, 25);
        doThing.setBounds(250, 150, 100, 25);
        typeHere.setBounds(100, 150, 150, 25);

    }

    public void actionPerformed(ActionEvent event){
        String check = event.getActionCommand();
        if(check.equals("Do a Thing")){
            input = typeHere.getText();
        }
        if(input != "0"){
            num1.setText(sorter.divQuarter(money));
            num2.setText(sorter.divQuarter(money));
            num3.setText(sorter.divHalf(money));
        }
    }

}

For those who wanted the MoneySorter.java:



    public MoneySorter(){

    }

    public String divQuarter(double moneyIn){
        String answer = Double.toString(moneyIn);
        return answer;
    }

    public String divHalf(double moneyIn){
        String answer = Double.toString(moneyIn);
        return answer;
    }
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Jackie
  • 23
  • 5

3 Answers3

2

I understand that your program is supposed to do the following.

User enters an amount of money in a JTextField and when she clicks on a JButton the JLabels show the entered amount in dollars, half-dollars and quarters (as per U.S. currency). My answer, below, is based on this understanding.

I don't know if making all the variables static is good or bad but I never use static class member variables in my Swing programs.

Here is my analysis of your code.

private double money = Double.parseDouble(input);

This line of code will be executed precisely once, when you launch class MoneySorterRunner. You want to do this every time the JButton is clicked, hence parsing the text entered into the JTextField should be performed in the actionPerformed method.

JPanel panel = new JPanel();
panel.setLayout(null);

It is almost never needed to set the layout manager to null. You can almost always find an appropriate layout manager or you can place one JPanel within another and use different layout managers for each JPanel in order to get the desired placement of components within the Swing application window.

JButton doThing = new JButton("Do a Thing");
doThing.setActionCommand("Do a Thing");

By default, the text of a JButton is also its action command so no need to explicitly set it.

frame.setLocation(200, 200);
frame.setLocationRelativeTo(null);

These are two different ways to set the location of the JFrame and they do not complement each other. Use one or the other, but not both.

frame.setVisible(true);

Only after you have created all the [GUI] components and added them to the JFrame should you make the JFrame visible. So this should be the last line of the code that creates your GUI.

doThing.setBounds(250, 150, 100, 25);

If you use a layout manager, you never need to call method setBounds.

if(input != "0"){

This is not the way to compare strings. Use method equals as you have done here

if(check.equals("Do a Thing")){

Here is my rewrite of your application. Note that since I could not find the code for class MoneySorter, in your question, I just created my own version of that class. The point is to show how to change the text of the JLabel after clicking on the JButton and not how to create the actual text to display.

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MoneySorterRunner implements ActionListener {
    private MoneySorter sorter = new MoneySorter();
    private JTextField typeHere = new JTextField();

    private JLabel num1;
    private JLabel num2;
    private JLabel num3;

    private void createAndShowGui() {
        JFrame frame = new JFrame("Money Calculator - v0.1a");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(createLabels(), BorderLayout.PAGE_START);
        frame.add(createForm(), BorderLayout.CENTER);
        frame.setSize(550, 250);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JPanel createForm() {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
        panel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
        typeHere = new JTextField(10);
        panel.add(typeHere);
        JButton doThing = new JButton("Do a Thing");
        doThing.addActionListener(this);
        panel.add(doThing);
        return panel;
    }

    private static JLabel createLabel(String text) {
        JLabel label = new JLabel(text);
        label.setFont(new Font("Arial", Font.PLAIN, 25));
        return label;
    }

    private JPanel createLabels() {
        JPanel panel = new JPanel(new GridLayout());
        num1 = createLabel("num1");
        panel.add(num1);
        num2 = createLabel("num2");
        panel.add(num2);
        num3 = createLabel("num3");
        panel.add(num3);
        return panel;
    }

    public static void main(String args[]) {
        new MoneySorterRunner().createAndShowGui();
    }

    public void actionPerformed(ActionEvent event){
        String check = event.getActionCommand();
        if(check.equals("Do a Thing")){
            String text = typeHere.getText();
            if (!text.isEmpty()) {
                double money = Double.parseDouble(text);
                num1.setText(sorter.divQuarter(money));
                num2.setText(sorter.divQuarter(money));
                num3.setText(sorter.divHalf(money));
            }
        }
    }
}

class MoneySorter {

    public String divQuarter(double money) {
        return "divQuarter(" + money + ")";
    }

    public String divHalf(double money) {
        return "divHalf(" + money + ")";
    }
}

This is how your GUI looked when I ran your original code (as posted in your question).

original app screen capture

This is how the GUI looks when running the code in this answer.

After launching

my app after launch screen capture

After entering a value and clicking the JButton

my app after button click

Abra
  • 19,142
  • 7
  • 29
  • 41
  • This is good but I specifically didn't want to use a layout so I could do it myself, also the other class only takes in the double money after it's been parsed and changes it back into a string to be displayed as one of the 3 labels called num1-3 that sit right below item1-3. item1-3 I never want to change those but num1-3 change to become whatever is put in the text field, for testing it just returns what it receives as a string, but later it will do something else, which is why MoneySorter is not included, if it were the program would start up and show 0.0 under the 3 top labels. – Jackie May 21 '21 at 13:06
  • this helps tho and thanks for the response, I will attempt to implement this however I still plan to leave out a pre done layout, personally I've never been a fan of those. – Jackie May 21 '21 at 13:08
  • 1
    I am glad to say I was able to successfully able to implement this solution, it might anger a few people that I decided to not use a layout manager, but I wanted absolute positioning in this and have better personal experience making the GUI layout myself. Once again thank you for the help! – Jackie May 21 '21 at 14:21
1

It looks like you forgot to set the ActionListener. You should also change your method to another name, because your method has the same name as the actionPerformed of the ActionListener.

doThing.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new MoneySorterRunner().actionPerformedMethod(e);
            }
        });
Tschogge
  • 86
  • 1
  • 7
  • 1
    I attempted to implement this but it did not help, I added it to my main method and replaced .actionPerformedMethod(e); with the name of the method which I changed to .buttonDidThing(e); am I implementing it wrong or something? – Jackie May 20 '21 at 17:17
  • did you also change the name of the method to ```public void buttonDidThing(ActionEvent event){}``` ? – Tschogge May 20 '21 at 17:26
  • 1
    Yes I did otherwise I would've gotten an error saying the method didn't exist – Jackie May 20 '21 at 17:52
  • 1
    I am curious btw, could part of the problem be that I'm doing everything with swing inside of the main method? I have seen the main method can't access non static things – Jackie May 20 '21 at 17:53
  • I don't know exactly what you mean and what it is in the main method, but you have to do ```new MoneySorterRunner().actionPerformedMethod(e)``` you can also do this from the main method. If something is non static, you need to make an object of it to access methods. Like ```Object name = new Object(); name.yourMethod()``` or ```new Object().yourMethod();``` – Tschogge May 21 '21 at 06:33
1

You forgot to add the ActionListener. In order to fix this, you need to do two things:

  1. Add this statement to your code, preferably near where you create the button (so that it is easier to keep track). -
doThing.addActionListener(this);
  1. When you write "public class", you also need this keyword: implements ActionListener - meaning your class (basically the first line) should look like:
public class MoneySorterRunner implements ActionListener

And that should make it work.

TheSj
  • 376
  • 1
  • 11
  • I also tried implementing this but I got something that said I can't use doThing.addActionListener(this); in a static context, specifically the "this" in the parentheses. I have no idea what this means tbh – Jackie May 20 '21 at 17:19