whiteElephant
whiteElephant

Reputation: 263

Displaying correct information in JPanel

I'm having trouble updating JPanels with new data. I'm working on a game, the basic concept of what I'm trying to do is load a player and display the items he holds in a JPanel (set out in a box layout) I am using a thread and loop to update the player items. This works fine for one player but my game allows for additional players which the user can switch between. When I switch to the next player I want their details to be loaded and updated. This doesn't work.

This is just a snippet of the code but I'm hoping someone will be able to see my problem.

    private JFrame frame;   
 private JPanel mainPanel;
 private Box Item1 Item2, Item3;
 static private JPanel centerPanel;


 private boolean playerLoaded;
 private Player currentPlayer;

 private Thread gameThread;




 public void run(){

    while (running){



        for (Player player:allPlayers){
            playerLoaded = false;
            currentPlayer = player;
            player.setCurrentTurn(true);

            while (player.isCurrentTurn()){

                if (playerLoaded != true){

                    loadPlayer(player);
                    loadItems(player);
                    playerLoaded = true;


                }

                if ((playerLoaded == true){

                updateItems(player);

                try {
                    Thread.sleep(999);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                }

            }

        }


        }
    }


 public void loadPlayer(Player player){
jlCurrentPlayer.setText("Player: " + player.getName());

 }

 public void loadItems(Player player){
int count = 1;

 centerPanel = new JPanel(new GridLayout(1,3));

for (Item Item : player.getAllItems()){

    if (count == 1) {
    Item1 = Box.createVerticalBox();
    Item1.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    JLabel jlItem = new JLabel(item.getName());
    Item1.add(jlItem);
    centerPanel.add(Item1);
    }
    else if (count ==2){
    Item2 = Box.createVerticalBox();
    Item2.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    JLabel jlItem = new JLabel(item.getName());
    Item2.add(jlItem);
    centerPanel.add(Item2);
    }
    else if (count ==3){
    Item3 = Box.createVerticalBox();
    Item3.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    JLabel jlItem = new JLabel(item.getName());
    Item3.add(jlItem);
    centerPanel.add(Item3);
    }

    mainPanel.add(centerPanel,BorderLayout.CENTER);

    count++;
}

 }


  public void updateItemstats(Player player){
int count = 1;
if (player.isCurrentTurn()){
for (Item item : player.getAllItems()){

    if ((count == 1) && (player.isCurrentTurn())) {
        Item1.add(Box.createVerticalGlue());
        Item1.add(new JLabel("Value: " + item.getstats().getValue()));
        Item1.add(new JLabel("Quality: " + item.getStats().getQuality()));
    }
    else if (count ==2){
        Item2.add(Box.createVerticalGlue());
        Item2.add(new JLabel("Value: " + item.getstats().getValue()));
        Item2.add(new JLabel("Quality: " + item.getStats().getQuality()));

    }
    else if (count ==3){
        Item3.add(Box.createVerticalGlue());
        Item3.add(new JLabel("Value: " + item.getstats().getValue()));
        Item3.add(new JLabel("Quality: " + item.getStats().getQuality()));

    }
 count++;

}
}
 }

 JButton jbNext = new JButton("Next Player");       

 jbNext.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            currentPlayer.setCurrentTurn(false);

        }
    });

For my main frame I am using a Border Layout. Whats happening when I switch players is basically the updated information is sometimes a mix of player 1 and 2. e.g.

value 25 Quality 60

value 50 Quality 20.

In addition if player 1 has 1 Item and player 2 has 3 Items and I switch from player 2 to 1 sometimes player 1 will have all of player 2 items instead of his own.

I thought it might be an issue with the Item1 2 and 3 panels so I tried to remove them on next player btn click but this just caused an exception. This may well be the problem still and I may not be removing them correctly.

Can anyone out there help me out with this?

Upvotes: 0

Views: 85

Answers (1)

Angelo Fuchs
Angelo Fuchs

Reputation: 9941

You should call setCurrentTurn(true) for the next Player in the next player action Listener.

Have you set the currentPlayer variable in Player to volatile? Important: Both the private Player currentPlayer and the private boolean currentPlayer in the Player.java must be volatile. (Have a look at http://javamex.com/tutorials/synchronization_volatile.shtml)

Also, use a Monitor and wait() instead of Thread.sleep that way you can use notify() to wake up the waiting Thread.

Here are some suggestions for your code, but be aware that you will have to do more (e.G. in the Player.java class that you did not show).

volatile List<Player> players = ...; // load your list of Player
volatile int currentPlayerIndex = 0;
volatile Player currentPlayer = null;
private final Object WAIT_MONITOR = new Object(); // yes, 'new Object()' !
[...]
public void run() throws InterruptedException {
    playerLoop:
    while(programRunning) { // maybe while(true)
        synchronized (WAIT_MONITOR) {
            loadPlayer(currentPlayer);
            loadItems(currentPlayer);

            updateItems(currentPlayer);
            WAIT_MONITOR.wait(1000);
        }
    }
}

[...]

JButton jbNext = new JButton("Next Player");       

jbNext.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        synchronized(WAIT_MONITOR) { // this causes that the contents of run() and this method do not run at the same time.
            currentPlayer.setCurrentTurn(false);
            if(players.size() > currentPlayerIndex + 1) // don't use >=
                currentPlayerIndex++;
            else
                currentPlayerIndex = 0; // reset at the end of the list
            currentPlayer = players.get(currentPlayerIndex);
            currentPlayer.setCurrentTurn(true);
            WAIT_MONITOR.notifyAll(); // that causes the wait() method above to be continued.
        }
    }
});

Upvotes: 1

Related Questions