我目前正在开发一个游戏,并且我试图实现一个健康栏,该健康栏会在每次玩家受到伤害时更新,我目前已经对其进行了设置,使其位于布局的单独面板中:
// menu is the bit with the health bar
ControlPanel menu = new ControlPanel(this);
window.add(menu.getMainPanel(), BorderLayout.NORTH);
// view is the part of the window the game runs in
window.add(view, BorderLayout.CENTER);
我听说要对其进行更新,您可以使用changelistener,但是我一直很难使它正常运行,这就是我到目前为止所要做的:
private JProgressBar healthProgressBar;
private Player player;
public ControlPanel(Game game) {
player = game.getPlayer();
healthProgressBar.setString(player.getHealth() + "/100");
healthProgressBar.setStringPainted(true);
healthProgressBar.setValue(player.getHealth());
healthProgressBar.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int oldHealth = player.getHealth();
player = (Player) e.getSource();
if (player.getHealth() != oldHealth) {
healthProgressBar.setValue(player.getHealth());
}
}
});
public JPanel getMainPanel() {
return mainPanel;
}
它将使进度条显示在我想要的位置,并具有我赋予的值,但是如果有人知道如何使它起作用,它将不会在玩家受到伤害时更新。非常感谢!
答案 0 :(得分:2)
好的,这是一个有点冗长的答案,但我只想展示一个使用侦听器进行松耦合和更新JProgressBar的示例
假设您有一个非GUI Player对象,该对象具有String名称属性和int health属性,并使用属性更改支持来允许添加侦听器。此类的摘要如下所示:
class Player {
public static final String HEALTH = "health"; // the name of the property of interest
public static final int HEALTH_MIN = 0;
public static final int HEALTH_MAX = 100;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private String name;
int health = 50; // value from 1 to 100
public Player(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
// any time this is called, listeners will be notified through the pcSupport object
public void setHealth(int health) {
int oldValue = this.health;
int newValue = health;
this.health = health;
// notify observers of change in the HEALTH property
pcSupport.firePropertyChange(HEALTH, oldValue, newValue);
}
public String getName() {
return name;
}
// allow listeners/observers to be added
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
// ....... other methods
}
请注意解耦-Player类不需要知道它显示在哪个GUI中,观察者将如何使用他们观察到的任何信息。
现在,我们将这个Player放在一个简单的GUI中,它是一个具有JSlider的JPanel,允许我们更改玩家的health属性的状态。此类的代码片段可能类似于:
class PlayerPanel extends JPanel {
private Player player;
private JSlider healthSlider = new JSlider(Player.HEALTH_MIN, Player.HEALTH_MAX, 0);
public PlayerPanel(Player player) {
this.player = player;
healthSlider.setValue(player.getHealth());
healthSlider.setMajorTickSpacing(20);
healthSlider.setMinorTickSpacing(5);
healthSlider.setPaintTicks(true);
healthSlider.setPaintLabels(true);
// call method to change the player's health when the slider changes
healthSlider.addChangeListener(clEvent -> healthChange());
JPanel namePanel = new JPanel();
namePanel.add(new JLabel("Player Name:"));
namePanel.add(Box.createHorizontalStrut(5));
namePanel.add(new JLabel(player.getName()));
setLayout(new BorderLayout());
add(namePanel, BorderLayout.PAGE_START);
add(healthSlider);
}
// ........ other methods
private void healthChange() {
player.setHealth(healthSlider.getValue());
}
// .......... other methods
}
然后在另一个具有JProgressBars的类中,我们可以在progressBar中显示播放器的健康状况,并在此健康状况发生变化时让侦听器更新progressBar:
// create a Player object
Player player = new Player(playerName);
// create a JProgressBar to show the health
final JProgressBar progressBar = new JProgressBar(Player.HEALTH_MIN, Player.HEALTH_MAX);
progressBar.setStringPainted(true);
progressBar.setValue(player.getHealth()); // set initial value
// add a PropertyChangeListener to Player to be notified when HEALTH changes
player.addPropertyChangeListener(Player.HEALTH, pcEvent -> setProgress(progressBar, player));
我们将从setProgress方法更新JProgressBar:
private void setProgress(JProgressBar progressBar, Player player) {
int health = player.getHealth();
progressBar.setValue(health);
}
整个工作示例如下:
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Window;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
@SuppressWarnings("serial")
public class JProgressHealth extends JPanel {
public static final String[] PLAYER_NAMES = {"John", "Steve", "Frank", "Judy", "Hillary", "Billy"};
private List<Player> players = new ArrayList<>();
public JProgressHealth(Window owner) {
setLayout(new GridLayout(0, 1));
for (String playerName : PLAYER_NAMES) {
Player player = new Player(playerName);
final JProgressBar progressBar = new JProgressBar(Player.HEALTH_MIN, Player.HEALTH_MAX);
progressBar.setStringPainted(true);
progressBar.setValue(player.getHealth());
player.addPropertyChangeListener(Player.HEALTH, pcEvent -> setProgress(progressBar, player));
JPanel titlePanel = new JPanel(new BorderLayout());
titlePanel.add(progressBar);
titlePanel.setBorder(BorderFactory.createTitledBorder(player.getName()));
add(titlePanel);
// create player panels to illustrate how this works
PlayerPanel playerPanel = new PlayerPanel(player);
JDialog dialog = new JDialog(owner, player.getName(), ModalityType.MODELESS);
dialog.add(playerPanel);
dialog.pack();
dialog.setLocationByPlatform(true);
dialog.setVisible(true);
}
}
// make JPanel wider
@Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int w = 3 * superSize.width;
int h = superSize.height;
return new Dimension(w, h);
}
private void setProgress(JProgressBar progressBar, Player player) {
int health = player.getHealth();
progressBar.setValue(health);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Health");
JProgressHealth mainPanel = new JProgressHealth(frame);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
@SuppressWarnings("serial")
class PlayerPanel extends JPanel {
private Player player;
private JSlider healthSlider = new JSlider(Player.HEALTH_MIN, Player.HEALTH_MAX, 0);
public PlayerPanel(Player player) {
this.player = player;
healthSlider.setValue(player.getHealth());
healthSlider.setMajorTickSpacing(20);
healthSlider.setMinorTickSpacing(5);
healthSlider.setPaintTicks(true);
healthSlider.setPaintLabels(true);
healthSlider.addChangeListener(clEvent -> healthChange());
JPanel namePanel = new JPanel();
namePanel.add(new JLabel("Player Name:"));
namePanel.add(Box.createHorizontalStrut(5));
namePanel.add(new JLabel(player.getName()));
setLayout(new BorderLayout());
add(namePanel, BorderLayout.PAGE_START);
add(healthSlider);
}
// make JPanel wider
@Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int w = 2 * superSize.width;
int h = superSize.height;
return new Dimension(w, h);
}
private void healthChange() {
player.setHealth(healthSlider.getValue());
}
public Player getPlayer() {
return player;
}
}
class Player {
public static final int HEALTH_MIN = 0;
public static final int HEALTH_MAX = 100;
public static final String HEALTH = "health";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private String name;
int health = 50; // value from 1 to 100
public Player(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
int oldValue = this.health;
int newValue = health;
this.health = health;
// notify observers of change
pcSupport.firePropertyChange(HEALTH, oldValue, newValue);
}
public String getName() {
return name;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
}