Changing text of JLabel where text is stats in another class

61 views Asked by At

I am making a game which has a store where in game coins can be spent. I want to display the amount of coins you have to spend. This value changes constantly as the game progresses. I have it capable of displaying the initial value and changing with purchases but it will not update from the other class.

Here is my code:

public StoreFrame(Run game,You y) {
    super("Store");
    theGame=game;
    setLayout(null);
    you=y;
    try {
        storeBack = ImageIO.read(new File("backgrounds/store.png"));
    } 
    catch (IOException e) {
    }

    //background
    setContentPane(new JLabel(new ImageIcon(storeBack)));

    coins = new JLabel("Coins: "+you.gettotCoins());//here is the problem
    coins.setFont(new Font("SanSerif", Font.BOLD, 18));
    coins.setForeground(Color.black);
    coins.setBounds(25, 25, 100, 100);
    add(coins);     

    setSize (800,600);  
    setResizable(false);    
    setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}

The class the text comes from:

public class You {

    private int totCoins;

    public You(int p) {
        totCoins=110;//starting money
    }

    public int gettotCoins() {
        return totCoins;
    }

    public void settotCoins(int subtract) {
        totCoins-=subtract;
    }
}

Please help

2

There are 2 answers

0
Mr Tsjolder from codidact On

Because using design patterns is good practice, you could consider using the Observer pattern. The idea is to make an interface defining one (or more) methods that can be called when something needs to be updated. All classes that are interested in the updates can then implement this interface and the updated subject keeps a list of those observers.

In your case, this means that you could define a CoinObserver interface (try to use meaningful names) like this:

public interface CoinObserver {

    void coinsChanged(int newAmount);
}

Next, a list of listeners needs to be kept where your amount of coins is stored. As I assume this is in the You class, your class would look as follows using the Observer pattern:

public class You {

    private int totCoins;
    private Collection<CoinObserver> coinObservers;

    public You(int p) {
        totCoins=110;
        coinObservers = new ArrayList<>(); //or any collection you like
    }

    public int getTotCoins() {
        return totCoins;
    }

    //Setters turn out to be very useful in this case if used correctly
    private void setTotCoins(int newCoins) {
        totCoins = newCoins;
        coinsChanged();
    }

    public void subtractCoins(int subtract) {
        setTotCoins(totCoins - subtract);
    }

    public void addCoinObserver(CoinObserver co) {
        coinObservers.add(co);
    }

    public void removeCoinObserver(CoinObserver co) {
        coinObservers.remove(co);
    }

    private void coinsChanged() {
        for(CoinObserver co : coinObservers) {
            co.coinsChanged(getTotCoins());
        }
    }
}

Finally, you will have to extend the JLabel for your coins to implement this interface as follows and let it "subscribe" itself as a CoinObserver:

public class CoinLabel extends JLabel implements CoinObserver {

    public CoinLabel(You you) {
        super("Coins: " + you.getTotCoins());
        setFont(new Font("SanSerif", Font.BOLD, 18));
        setForeground(Color.black);
        setBounds(25, 25, 100, 100);
        you.addCoinObserver(this);
    }

    @Override
    public void coinsChanged(int newAmount) {
        setText("Coins: " + newAmount);
    }
}

Note that this solution will gather a lot of observers, because they are never removed from you. This could be solved by overwriting the dispose() method, but then you should use setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE); (although I'm not completely sure about that) and keep a field to the You in order to use it outside the constructor.

This might seem like a lot of work to call setText("Coins: " + you.getTotCoins()) method as you suggested, but it might be worth the while if your code starts to get more complex. Some of the main advantages might be:

  • Automatisation: You don't need to think about writing label.setText("...") every time you change the amount of coins, because every time a new value is set for the coins, the observers will be notified.
  • Extensibility: Imagine you would want to make some kind of percentage-bar that indicates how much of the maximum possible amount of money you have. Instead of having to draw your bar over and over again everywhere the amount of money might change, you can just make your bar a CoinObserver, implement the coinsChanged(int newAmount) method and add it to the list of observers without a need to change anything to your existing code.
  • Looser coupling: If you aim for low coupling, the observer pattern makes sure that you don't really need to know about the You class in your GUI (you only need the Observer-interface i.e. addCoinObserver(co) and removeCoinObserver(co)). Also your You class won't ever know what the observers exactly are, it only knows about the interface of CoinObserver. This allows to program towards the MVC model and is generally good practice.

and there are probably more. A last thing I would like to note here: if you only change the value of your coins in one place and it is very unlikely that you would be interested in coins anywhere else, you shouldn't be using the observer pattern. Design patterns can help you in all possible ways, but they shouldn't be overused.

0
Collin On

I found a way to do this. In the classes that access this frame, just say

theStore.coins.setText("Coins: "+you.gettotCoins());

This will pass in the new text into the class and will cause it to update

Thanks to all above who helped put me on the right track