我无法弄清楚为什么JPanel没有刷新(我尝试过revalidate();和repaint();

时间:2014-06-17 03:59:01

标签: java swing jpanel refresh

所以我遇到的问题是游戏玩法()。当我们(我自己没有写这个代码所以我可能在回答某些事情时遇到一些麻烦)尝试将ImageComponent更新为另一个图像时,刷新JPanel以显示两个新图像,延迟代码1秒,然后显示下一张图片,它没有用。当我运行代码时,屏幕会冻结预期的延迟,然后会出现在while循环的最后一次迭代中显示的内容。基本上,它从开始的2个图像跳到最后的2个。即使我拿出了repaint();和revalidate();它做了同样的事情,所以我相信它根本不令人耳目一新。我该怎么办?

import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;  
import javax.swing.Timer;

public class Background {

private Pokemon user;
private Pokemon computer;
private final JFrame frame = new JFrame();
private final JLabel userMove = new JLabel("");
private final JLabel aiMove = new JLabel("");
private final JLabel hu = new JLabel("");
private final JLabel pch = new JLabel("");
private final JLabel moveFirst = new JLabel("");
private final JPanel mainPanel = new JPanel();
private JPanel backS = new JPanel( new FlowLayout(FlowLayout.LEFT, 0, 0)); //coderanch.com, written by David Bryon
private JComponent left;
private JComponent right;
private final long PERIOD = 500L; // Adjust to suit timing
private long lastTime = System.currentTimeMillis() - PERIOD;
Timer timer;

public void execute(int choice){
    frame.setSize( 1000, 500);
    backS.setSize(300, 1000);
    final JPanel buttonPanel = new JPanel();


    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);



    //user choice for a pokemon, takes number from selection screen
    if(choice == 1){
        user = new Kyogre();
        computer = aiRandom();
    }
    else if(choice == 2){
        user = new Groudon();
        computer = aiRandom();
    }
    else if(choice == 3){
        user = new Mewtwo();
        computer = aiRandom();
    }
    else if(choice == 4){
        user = new Arceus();
        computer = aiRandom();
    }
    else if(choice == 5){
        user = new Pikachu();
        computer = aiRandom();
    }
    else if(choice == 6){
        user = new Snorlax();
        computer = aiRandom();
    }



    //health bars
    JPanel healthBarUser = new JPanel();
    healthBarUser.setSize(500, 100);
    healthBarUser.setBackground(Color.GRAY);
    String h1 = "";
    for(int i = 0; i < user.getHealth(); i+=10){
        h1 += "|";
    }
    String h2 = "";
    for(int i = 0; i < computer.getHealth(); i+=10){
        h2 += "|";
    }
    /*try{
        Thread.sleep(100);
    }
    catch(Exception e)
    {
        System.out.println("Exception caught");
    }*/
    hu.setText("Your HP: " + h1 + user.getHealth() +"      ");
    healthBarUser.add(hu);

    JPanel healthBarPC = new JPanel();
    healthBarPC.setBackground(Color.GRAY);
    healthBarPC.setSize(500, 100);

    pch.setText("Computer's HP: " + h2+ computer.getHealth());
    healthBarUser.add(pch);
    left = user.leftSide();
    right = computer.rightSide();
    backS.add(left);
    backS.add(right);



    //move buttons
    JButton button1 = new JButton(user.accessMoves(0).getName());
    JButton button2 = new JButton(user.accessMoves(1).getName());
    JButton button3 = new JButton(user.accessMoves(2).getName());
    JButton button4 = new JButton(user.accessMoves(3).getName());


    userMove.setText( "You used: " );
    aiMove.setText( "Computer used: " + "                       ");


    moveFirst.setText("_____ attacked first");        

    //4 different button listeners
    class b1Listener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            gamePlay(0);
            if(computer.getHealth() <=0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(0);
            }
            else if(user.getHealth() <= 0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(1);
            }

          }
       }

    class b2Listener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            gamePlay(1);
            if(computer.getHealth() <=0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(0);
            }
            else if(user.getHealth() <= 0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(1);
            }
          }
       }

    class b3Listener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            gamePlay(2);
            if(computer.getHealth() <=0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(0);
            }
            else if(user.getHealth() <= 0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(1);
            }
          }
       }

    class b4Listener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            gamePlay(3);
            if(computer.getHealth() <=0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(0);
            }
            else if(user.getHealth() <= 0){
                frame.remove(mainPanel);
                frame.setSize(1050, 500);
                gameEnd(1);
            }
          }
       }

//adds liteners to buttons
    button1.addActionListener( new b1Listener() );
    button2.addActionListener( new b2Listener());
    button3.addActionListener( new b3Listener() );
    button4.addActionListener( new b4Listener() );



//adds all panels, text fields, etc to final pane
    mainPanel.add(healthBarUser);
    mainPanel.add(healthBarPC);
    mainPanel.add(backS);
    mainPanel.add(button1);
    mainPanel.add(button2);
    mainPanel.add(button3);
    mainPanel.add(button4);
    mainPanel.add(userMove);
    mainPanel.add(aiMove);
    mainPanel.add(moveFirst);
    mainPanel.setBackground(Color.GRAY);

    frame.add(mainPanel);
    frame.setVisible(true);

}

//returns user's pokemon
public Pokemon getUserPokemon(){
    return user;
}

//returns computer's pokemon
public Pokemon getAIPokemon(){
    return computer;
}

//chooses a random pokemon for the computer
private Pokemon aiRandom(){
    int s = (int)(Math.random() * 6 );

    if(s == 0)
        return new Kyogre();
    if(s == 1)
        return new Groudon();
    if(s == 2)
        return new Mewtwo();
    if(s == 3)
        return new Arceus();
    if(s == 4)
        return new Pikachu();
    if(s == 5)
        return new Snorlax();
    return null;
}

//generates a random number so we can choose an ai move
private int aiMove(){
    int i = (int)(Math.random() * 4);
    return i;
}

//creates pop-up window if somebody's health drops to 0
private void gameEnd(int i){
    String rt;
    if(i == 0)
        rt = "Congratulations! You won! " + computer.getClass().getName() + " fainted.                                       Would you like to play again?";
    else if(i == 1)
        rt = "Sorry. You lost to the computer. " + user.getClass().getName() + " fainted.  Would you like to play again?";
    else 
        rt = "You and the computer tied. Would you like to play again?";

    JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
    p.add(user.leftSide());
    p.add(computer.rightSide());

    JLabel  j1 = new JLabel(rt);
    ButtonGroup groupD = new ButtonGroup();
    final JRadioButton y = new JRadioButton("Yes"); //allows us to run program with f already selected
    final JRadioButton n = new JRadioButton("No", true);
    groupD.add(y);
    groupD.add(n);
    JButton button = new JButton("Select");
    class ConvertListener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            SelectionScreen s = new SelectionScreen();
            if(y.isSelected()){
                s.execute();
                frame.setVisible(false);
                frame.dispose();
            }
            else if(n.isSelected()){
                frame.setVisible(false);
                frame.dispose();
            }
        }
    }
    ActionListener listener = new ConvertListener();
    button.addActionListener(listener);
    p.add(j1);
    p.add(y);
    p.add(n);
    p.add(button);

    frame.add(p);
    frame.setVisible(true);
}

//runs and updates health bar
private String healthBar(Pokemon x){
    String rt = "";
    for(int i = 0; i < x.getHealth(); i +=10 ){
        rt += "|";
    }
    return rt;
}

private void gamePlay(int us){

    String h1 = "";
    String h2 = "";
    int c;
    do{
        c = aiMove();
    }while(computer.accessMoves(c).getPP() <= 0);


    if(user.accessMoves(us).getPP() <= 0 ){
         JOptionPane.showMessageDialog(frame, "The move you selected has no PP left. Select another.");
         return;
    }
    long lastTime = System.currentTimeMillis();           
    if(user.getSpeed() >= computer.getSpeed()){  //if user's speed is quicker, computer gets attacked first
           computer.updateHealth(user, us);
           userMove.setText("You used: " + user.accessMoves(us).getName());
           user.accessMoves(us).lowerPP(); 
           h2 = healthBar(computer);                       //health bar is changed

           int usCount = 0;
           int compCount= 0;



           while(usCount < user.leftNumFramesMove(us)){
               long thisTime = System.currentTimeMillis();
               if ((thisTime - lastTime) >= PERIOD) {
               lastTime = thisTime;
             //  backS.remove(left);
             //  backS.remove(right);
               if(us == 0)
                   left = user.LeftSideMove0(usCount + 1);
               else if(us == 1)
                   left = user.LeftSideMove1(usCount + 1);
               else if(us == 2)
                   left = user.LeftSideMove2(usCount + 1);
               else
                   left = user.LeftSideMove3(usCount + 1);
               //backS.add(left);
              // backS.add(right);
               backS.revalidate();

               usCount += 1;
             }
             usCount += 1;
           }
           while(compCount < user.rightNumFramesMove(us)){
                 long thisTime = System.currentTimeMillis();
                if ((thisTime - lastTime) >= PERIOD) {
                lastTime = thisTime;
               if(us == 0)
                  left = user.LeftSideMove0(usCount);
               else if(us == 1)
                   left = user.LeftSideMove1(usCount);
               else if(us == 2)
                   left = user.LeftSideMove2(usCount);
               else
                   left = user.LeftSideMove3(usCount);

               if(us == 0)
                  right = user.RightSideMove0(compCount + 1, computer);
               else if(us == 1)
                  right = user.RightSideMove1(compCount + 1, computer);
               else if(us == 2)
                  right = user.RightSideMove2(compCount + 1, computer);
               else
                  right = user.RightSideMove3(compCount, computer);
              // backS.add(left);
               //backS.add(right);
               backS.revalidate();



               compCount += 1;
             }
           }

           pch.setText("Computer's HP: " + h2+ computer.getHealth());
           moveFirst.setText("You attacked first.");

           if(computer.getHealth() == 0){                  //if computer dies, user wins
               return;
            }

        /* backS.remove(left);
         backS.remove(right);
         left = new ImageComponent(user.getName() + "Left.jpg");
         right = new ImageComponent(computer.getName() + "Right.jpg");
         backS.add(left);
         backS.add(right);
         backS.repaint();*/
           user.updateHealth(computer, aiMove());
           aiMove.setText("Computer used: " + computer.accessMoves(c).getName() + "                       "); 
           computer.accessMoves(c).lowerPP();
           h1= healthBar(user);
           hu.setText("Your HP: " + h1 + user.getHealth() +"      ");
           if(user.getHealth() == 0){
               return;
            }
      }
      else {
         user.updateHealth(computer, aiMove());
         aiMove.setText("Computer used: " + computer.accessMoves(c).getName() + "                       "); 
         computer.accessMoves(c).lowerPP();
         h1= healthBar(user);
         hu.setText("Your HP: " + h1 + user.getHealth() +"      ");
         moveFirst.setText("Computer attacked first.");

         computer.updateHealth(user, us);
         userMove.setText("You used: " + user.accessMoves(us).getName());
         user.accessMoves(us).lowerPP();
         h2 = healthBar(computer);

        //creates pause between player move and computer move
           int usCount = 0;
           int compCount= 0;
           while(usCount < user.leftNumFramesMove(us)){
                 long thisTime = System.currentTimeMillis();
                if ((thisTime - lastTime) >= PERIOD) {
                lastTime = thisTime;
              // backS.remove(left);
               //backS.remove(right);
               if(us == 0)
                  left = user.LeftSideMove0(usCount + 1);
               else if(us == 1)
                   left = user.LeftSideMove1(usCount + 1);
               else if(us == 2)
                   left = user.LeftSideMove2(usCount + 1);
               else if(us == 3)
                   left = user.LeftSideMove3(usCount + 1);
               right = computer.rightSide();
             //  backS.add(left);
             //  backS.add(right);
               frame.revalidate();
               frame.repaint();
               backS.revalidate();
               backS.repaint();


               usCount += 1;
           }
           }
           usCount += 1;
           while(compCount < user.rightNumFramesMove(us)){
                 long thisTime = System.currentTimeMillis();
                if ((thisTime - lastTime) >= PERIOD) {
                lastTime = thisTime;
              // backS.remove(left);
             //  backS.remove(right);
                if(us == 0)
                  left = user.LeftSideMove0(usCount);
               else if(us == 1)
                  left = user.LeftSideMove1(usCount);
               else if(us == 2)
                  left = user.LeftSideMove2(usCount);
               else if(us == 3)
                  left = user.LeftSideMove3(usCount);

               if(us == 0)
                  right = user.RightSideMove0(compCount + 1, computer);
               else if(us == 1)
                  right = user.RightSideMove1(compCount + 1, computer);
               else if(us == 2)
                  right = user.RightSideMove2(compCount + 1, computer);
               else if(us == 3)
                  right = user.RightSideMove3(compCount + 1, computer);
              // backS.add(left);
              // backS.add(right);
               frame.revalidate();
               frame.repaint();
               backS.revalidate();
               backS.repaint();
               ;
               compCount += 1;
           }
          }


         pch.setText("Computer's HP: " + h2+ computer.getHealth());
         if(computer.getHealth() == 0){ 
               return;
         }
        /*backS.remove(left);
         backS.remove(right);
         left = new ImageComponent(user.getClass().getName() + "Left.jpg");
         right = new ImageComponent(computer.getClass().getName() + "Right.jpg");
         backS.add(left);
         backS.add(right);
         backS.repaint(); */
       }
}

}

1 个答案:

答案 0 :(得分:1)

基本上,你阻止事件调度线程,阻止它更新屏幕。

gamePlay方法存在之前(并且actionPerformed方法存在),屏幕上不会绘制任何内容。

请查看Concurrency in Swing了解详情。

通常,您应该考虑使用javax.swing.Timer在Swing中执行基本动画。您可以使用Thread,但这只会使问题复杂化

有关详细信息,请查看How to use Swing Timers

另外,请记住,Swing不是线程安全的。如果需要更新UI,则必须在Event Dispatching Thread

的上下文中执行此操作

<强>更新...

好的,所以这真的很复杂。

基本上,javax.swing.Timer在指定的时间段内在EDT之外等待,然后触发更新,以便在EDT的上下文中通知已注册的ActionListener

这意味着,当您启动Timer时,代码将在Timer等待时继续运行...

例如......

Timer timer = new Timer(PERIOD, new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        // Executed later...
    }
});
timer.start();
// Not waiting, continue execution...

这意味着,根据您的代码,您需要设计某种“执行后”链,或者更好地设置动画,例如......

private void gamePlay(int us) {

    String h1 = "";
    String h2 = "";
    int c;
    do {
        c = aiMove();
    } while (computer.accessMoves(c).getPP() <= 0);

    if (user.accessMoves(us).getPP() <= 0) {
        JOptionPane.showMessageDialog(frame, "The move you selected has no PP left. Select another.");
        return;
    }
    long lastTime = System.currentTimeMillis();
    if (user.getSpeed() >= computer.getSpeed()) {  //if user's speed is quicker, computer gets attacked first
        computer.updateHealth(user, us);
        userMove.setText("You used: " + user.accessMoves(us).getName());
        user.accessMoves(us).lowerPP();
        h2 = healthBar(computer);                       //health bar is changed

        //......
        MoveAnimationHandler handler = new MoveAnimationHandler(this, us, user, computer, new Runnable() {
            @Override
            public void run() {
                pch.setText("Computer's HP: " + h2 + computer.getHealth());
                moveFirst.setText("You attacked first.");

                if (computer.getHealth() == 0) {                  //if computer dies, user wins
                    return;
                }

                /* backS.remove(left);
                 backS.remove(right);
                 left = new ImageComponent(user.getName() + "Left.jpg");
                 right = new ImageComponent(computer.getName() + "Right.jpg");
                 backS.add(left);
                 backS.add(right);
                 backS.repaint();*/
                user.updateHealth(computer, aiMove());
                aiMove.setText("Computer used: " + computer.accessMoves(c).getName() + "                       ");
                computer.accessMoves(c).lowerPP();
                h1 = healthBar(user);
                hu.setText("Your HP: " + h1 + user.getHealth() + "      ");
                if (user.getHealth() == 0) {
                    return;
                }
            }
        });

        Timer timer = new Timer(40, handler);
        timer.start();

MoveAnimationHandler ....

public class MoveAnimationHandler implements ActionListener {

    private int usCount = 0;
    private int compCount = 0;
    private Pokemon user;
    private Pokemon computer;

    private int left;
    private int right;

    private int us;
    private JComponent parent;

    private Runnable whenDone;

    public MoveAnimationHandler(JComponent parent, int us, Pokemon user, Pokemon computer, Runnable whenDone) {
        this.parent = parent;
        this.user = user;
        this.computer = computer;
        left = user.leftSide();
        right = computer.rightSide();
        this.us = us;
        this.whenDone = whenDone;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (usCount < user.leftNumFramesMove(us) && compCount < user.rightNumFramesMove(us)) {

            if (usCount < user.leftNumFramesMove(us)) {
                if (us == 0) {
                    left = user.LeftSideMove0(usCount + 1);
                } else if (us == 1) {
                    left = user.LeftSideMove1(usCount + 1);
                } else if (us == 2) {
                    left = user.LeftSideMove2(usCount + 1);
                } else {
                    left = user.LeftSideMove3(usCount + 1);
                }
                usCount += 1;
            }

            if (compCount < user.rightNumFramesMove(us)) {
                if (us == 0) {
                    left = user.LeftSideMove0(usCount);
                } else if (us == 1) {
                    left = user.LeftSideMove1(usCount);
                } else if (us == 2) {
                    left = user.LeftSideMove2(usCount);
                } else {
                    left = user.LeftSideMove3(usCount);
                }

                if (us == 0) {
                    right = user.RightSideMove0(compCount + 1, computer);
                } else if (us == 1) {
                    right = user.RightSideMove1(compCount + 1, computer);
                } else if (us == 2) {
                    right = user.RightSideMove2(compCount + 1, computer);
                } else {
                    right = user.RightSideMove3(compCount, computer);
                }
                compCount += 1;
            }

            parent.repaint();

        } else {

            ((Timer) e.getSource()).stop();
            whenDone.run();

        }
    }
}

现在,情况变得更糟,因为你的ActionListener依赖于输出,所以你需要一些方法来链接这些调用......

class b1Listener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        gamePlay(0, new Runnable() {
            @Override
            public void run() {
                if (computer.getHealth() <= 0) {
                    frame.remove(mainPanel);
                    frame.setSize(1050, 500);
                    gameEnd(0, null);
                } else if (user.getHealth() <= 0) {
                    frame.remove(mainPanel);
                    frame.setSize(1050, 500);
                    gameEnd(1, null);
                }
            }
        });
    }
}

private void gamePlay(int us, final Runnable doAfter) {
    //...
    if (user.getSpeed() >= computer.getSpeed()) {  //if user's speed is quicker, computer gets attacked first
        //...
        MoveAnimationHandler handler = new MoveAnimationHandler(this, us, user, computer, new Runnable() {
            @Override
            public void run() {
                //...
                doAfter.run();
            }
        });

        Timer timer = new Timer(40, handler);

    } else {
        //...
    }
}

这就是我所说的“因为你想要动画完成后执行”

关于帖子的开头,我会认真地重新考虑整个设计......

您应该查看Model-View-Controller模式和Observer Pattern

这将允许您将游戏的各个元素分离到孤立的责任区域,同时提供有关各种状态更新的急需通知,以使它们保持同步...