Make a JPanel Change After ActionListener

2019-09-20 07:02发布

问题:

I have to make a game for a school project in CS. I want to make it so that a person may input their name and all subsequent panels will have their name on it. I am using a card layout, which works for the most part. When I run the game and input the name, it works specifically on that card. However, when I go to the next card, where the String name is supposed to appear, it appears as null. My suspicion is that the program creates all of the cards before given the chance to accept the name input and is therefore failing. My teacher doesn't really know how to do it either.

Here is a segment of the code:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    public class NovelCards extends JFrame {
   private String name;
   private CardLayout cards;
   private JTextField txt = new JTextField(10);
   private JLabel label = new JLabel();
   public NovelCards() {
      super("Novel");
      masterPanel = new JPanel();
      cards = new CardLayout();
      txt.addActionListener( new ActionListener(){
          public void actionPerformed(ActionEvent e){
            name = txt.getText();
            label.setText(name);
          }
      });      
      button2 = new JButton("Next");
      button2.addActionListener(new NextListener());
      JPanel card2 = new JPanel();
      card2.add(button2);
      card2.add(txt);
      card2.add(label);
      card2.add(new JLabel(" Enter your name "));

      JButton button3 = new JButton("Next");
      button3.addActionListener(new NextListener());
      JPanel card3 = new JPanel();
      card3.add(new JLabel("Hello there, " + name + "!"));
      card3.add(button3);

      masterPanel.setLayout(cards); 
      masterPanel.add("2",card2);
      masterPanel.add("3",card3);
      this.setContentPane(masterPanel);
      cards.show(masterPanel, "1");
 }

 public class NextListener implements ActionListener{
  public void actionPerformed(ActionEvent event){
     cards.next(masterPanel);
 }

Here are also some photos of the program when running.

Here is the name enter screen after picking a name and hitting enter:

And then here is the subsequent card:

Thanks in advance for the help! (I would have directly posted the images but I don't have enough reputation)

回答1:

The question you need to ask yourself is, how would all the other cards/panels know what the value of the name is?

A simple solution would be to pass the name to all the panels. This becomes problematic when you want to add new cards/panels in, as you need to constantly update the code, sure, you could use a List or array and have all the cards/panels implement a common interface...

Or you could simply use a "model" of some kind, which all the cards/panels shared a reference to. This would allow you more simply share data between them without having to mess around to much

so if you could perhaps direct me to what I need to learn to pass name to another panel?

Make a class, preferably starting with an interface, which acts as a container for the data, this becomes your model...

public interface NovelCardsModel {
    public String getName();
    public void setName(String name);

    public void addPropertyChangeListener(PropertyChangeListener listener);
    public void removePropertyChangeListener(PropertyChangeListener listener);

    // Add accessors to any other data you might think
    // you need to share
}

Now, create a implementation of the model

public class DefaultNovelCardsModel implements NovelCardsModel {
    private PropertyChangeSupport propertyChangeSupport;
    private String name;

    public DefaultNovelCardsModel() {
        propertyChangeSupport = new PropertyChangeSupport(this);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String value) {
        if (value == null || !value.equals(name)) {
            String old = name;
            name = value;
            propertyChangeSupport.firePropertyChange("name", old, name);
        }
    }

    @Override
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    @Override
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }


}

For each panel who is going to need to know the name, you need to pass the same instance of the model to it...

DefaultNovelCardsModel model = new DefaultNovelCardsModel();
masterPanel = new MasterPane(model);
// All the other cards.

Each panel which wants to know when the name changes, they need to register a PropertyChangeListener and monitor for changes to the name property

public class MasterPanel extends JPanel {

    private NovelCardsModel model;

    public MasterPanel(NovelCardsModel model) {
        this.model = model;
        this.model.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("name".equals(evt.getPropertyName())) {
                    // Name has changed
                }
            }
        });
    }

}