How to update a JLabel when a JLabel in another class updates?

228 views Asked by At

I've hit a roadblock on this one and was hoping for some insight.

Here's the basic gist of what I'm trying to accomplish:

-I have a piece class (extending JPanel) that has an array of JRadioButton, as well as a JLabel that updates according to which button is selected. This part works fine.

-I have a "master" JFrame class that calls a couple different pieces and puts them on a frame - did this to keep things from getting unwieldy, it's easier to have each piece be its own class.

-For various purposes, I want to put a JLabel on the master frame that also shows which button is selected - in essence, I want to put a JLabel that is a copycat of the one in the piece class and updates whenever the piece label does. I don't know if I'm just being dumb but I can't get the one on the master to update whenever the piece one does - it just stays at the initial one. Is there a way to have this label update whenever the other one does?

"Piece" (basic example, not the real thing):

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.event.*;

import java.util.*;

public class Piece2 extends JPanel {

    //variables
    final JLabel on = new JLabel("NONE");

    String names[] = {
    "button 1","button 2","button 3"
    };

    private ActionListener buttonAction = new ActionListener(){
        public void actionPerformed (ActionEvent ae){
            String buttonText = ((JRadioButton) ae.getSource()).getText();
            on.setText(buttonText);
        }
    };

    void createList(){

        Box contentPanel = Box.createVerticalBox();
        ButtonGroup buttons123 = new ButtonGroup();

        final JRadioButton choiceButtons[]=new JRadioButton[names.length];
        for(int i=0;i<(names.length);i++){
            choiceButtons[i] = new JRadioButton(names[i]);
            choiceButtons[i].addActionListener(buttonAction);
            buttons123.add(choiceButtons[i]);
            contentPanel.add(choiceButtons[i]);
        }
        contentPanel.add(on);

        this.add(contentPanel);
        setVisible(true);

    };

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new Piece2().createList();

    }

    }

"MASTER" (again, very bare-bones example):

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.Timer;
import javax.swing.event.*;

import java.util.*;


public class CollectGUI extends JFrame{
    JLabel p2on = new JLabel("NONE");

    private void createDialog(){
        this.setSize(2000,1000);
        this.setLocation(0,0);
        this.setTitle("TITLE");
        JPanel mainpanel = new JPanel();
        mainpanel.setLayout(new BorderLayout());

        final Piece2 piece = new Piece2();
        piece.createList();
        mainpanel.add(piece, BorderLayout.WEST);

        //THIS IS THE PART WHERE I GET STUCK
        p2on.setText(piece.on.getText());
        //I KNOW IT ONLY SETS IT ONCE, HOW DO I GET IT TO UPDATE WHEN ON DOES?

        mainpanel.add(p2on, BorderLayout.EAST);
        this.add(mainpanel);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new CollectGUI().createDialog();
    }

}

So like I said I can get the label on there and set it once, but haven't figured out how to get it to update whenever on does... is there a way to "append" to the piece-class action listener from the master class? Or some kind of listener I can add to the p2on label that listens for when the on label changes? I'm pretty stumped. Thank you for your help!!

1

There are 1 answers

0
MadProgrammer On

You could use some kind of Observer Pattern, where both the JPanel and frame use a common object/model to make changes to the current state of the game, but which also provides event notifications so that the two can update themselves accordingly

This would also be related to Model-View-Controller, which would allow you to separate the visuals from the logic, decoupling your code

I'd prefer to have a model which controlled the logic and notified interested parties, but in your case, you "could" just use a PropertyChangeListener...

So, in your Piece2 class's ActionListener, you would need to trigger a property change event...

private ActionListener buttonAction = new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
        String buttonText = ((JRadioButton) ae.getSource()).getText();
        on.setText(buttonText);
        firePropertyChange("button", null, buttonText);
    }
};

And in your CollectionGUI, monitor for that event

piece.addPropertyChangeListener("button", new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        p2on.setText(piece.on.getText());
    }
});

I'd also discourage you from extending directly from a top level container like JFrame, it locks you into a single use-case and reduces the re-usability of your class and you're not really adding any new functionality to the class either