在 CardLayout 中重绘字符串

Redraw strings in CardLayout

我已经使用 CardLayout 制作了一款游戏,并且有一个用于排行榜的 JPanel。在排行榜中,我读取了两个文件(一个有名称,一个有时间),对它们进行排序并绘制前 5 个最快的时间,如下所示:

private void setBoard(){
        reset();
        try{
            br = new BufferedReader (new FileReader("username.txt"));
            accounts = ""+br.readLine().trim();
            arrNames = accounts.split(" ");
            br.close();
            br = new BufferedReader (new FileReader("time.txt"));
            allTimes = ""+br.readLine().trim();
            arrTimesTemp = allTimes.split(" ");
            arrTime = new double [arrTimesTemp.length];
            br.close();
        } catch (Exception er){
            System.out.print("Error" + er);
        }   
        for (int i=0;i<arrTime.length;i++)
            arrTime[i]=Double.parseDouble(arrTimesTemp[i]);;
        scores = new Score[arrTime.length];
        for (int i=0;i<arrTime.length;i++)
            scores[i] = new Score (arrNames[i],arrTime[i]);
        Arrays.sort(scores, new MyComparator());

        System.out.println("\n\n\n");
        for (int i=0;i<arrTime.length;i++)
            System.out.println(arrTime[i]+" "+arrNames[i]);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(title, getWidth()/2-title.getWidth()/2+10, 125, this);
        g.drawImage(txt, getWidth()/2-txt.getWidth()/2+10, 250, this);
        setBoard();
        g.setFont(new Font("Serif", Font.PLAIN, 25));
        g.setColor(Color.white);

        for (int i=0;i<5;i++){
            g.drawString((i+1)+"-", numX, lineY);
            g.drawString(scores[i].getName(), nameX, lineY);
            g.drawString(""+scores[i].getTime(), timeX, lineY);
            g.drawString("s", 515, lineY);
            lineY+=40;
        }
    }

第一次打开排行榜没有问题。但是,如果我 return 到菜单然后返回排行榜,则不会绘制字符串,但会绘制图像。我也没有得到任何错误。我不明白为什么会这样。

我如何return进入菜单:

public void actionPerformed(ActionEvent e) {
        if (e.getSource()==back)
            RunGame.card.first(RunGame.c);
    }

如何从菜单进入排行榜:

    else if (e.getSource()==d) //d is a JButton
            RunGame.card.show(RunGame.c,"Leaderboard");

leaderboard first time leaderboard when return to it

I solved my problem. I just had to reset numX nameX timeX lineY each time I switched to leaderboard

好吧,我们吸取了教训,全局状态是一件坏事...

好的,由于我花了一些时间将示例放在一起,所以我 post 它是为了演示共享状态的基本概念。

此示例创建了一个在主视图之间共享的 LeaderBoardModel。这允许在代码的不同方面之间共享状态,而无需明确了解它的实际工作方式 - 模型成为一个独立的工作单元并且可以管理它自己的状态。

这里的另一个方面是尽可能快地保持绘制路径 - 因此,即使在这个示例中,也可以考虑对列表进行排序和拆分以进行优化......但我们并没有尝试达到 200fps ...所以,平衡...

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                LeaderBoardModel model = new LeaderBoardModel();
                JFrame frame = new JFrame();
                frame.setLayout(new GridBagLayout());

                GridBagConstraints gbc = new GridBagConstraints();
                gbc.weightx = 1;
                gbc.weighty = 1;
                gbc.gridx = 0;
                gbc.gridy = 0;

                CardLayout cardLayout = new CardLayout();

                JPanel mainPane = new JPanel(cardLayout);
                mainPane.add(new GamePanel(model), "main");
                mainPane.add(new LeaderBoardPanel(model), "leaderBoard");

                cardLayout.show(mainPane, "main");

                frame.add(mainPane, gbc);

                JPanel buttons = new JPanel(new GridBagLayout());
                JButton main = new JButton("Main");
                JButton board = new JButton("Board");

                buttons.add(main);
                buttons.add(board);

                main.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        cardLayout.show(mainPane, "main");
                    }
                });
                board.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        cardLayout.show(mainPane, "leaderBoard");
                    }
                });

                gbc.weightx = 1;
                gbc.weighty = 0;
                gbc.gridy++;
                frame.add(buttons, gbc);

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    // I'd prefer to use interfaces as a base line concept, but, this is
    // is a demonstration of a concept, not a tutorial
    public class Score implements Comparable<Score> {

        private String name;
        private int score;

        public Score(String name, int score) {
            this.name = name;
            this.score = score;
        }

        public String getName() {
            return name;
        }

        public int getScore() {
            return score;
        }

        @Override
        public int compareTo(Score o) {
            return o.score - score;
        }

        @Override
        public String toString() {
            return name + " ~ " + score;
        }

    }

    // I'd prefer to use interfaces as a base line concept, but, this is
    // is a demonstration of a concept, not a tutorial
    public class LeaderBoardModel {

        private List<Score> scores;

        public LeaderBoardModel() {
            // This is where you'd consider loading the scores from
            // the original file...
            scores = new ArrayList<>(25);

            Random rnd = new Random();

            add(new Score("Shekhar", rnd.nextInt(99) + 1));
            add(new Score("Priyanka", rnd.nextInt(99) + 1));
            add(new Score("Vivi", rnd.nextInt(99) + 1));
            add(new Score("Darwin", rnd.nextInt(99) + 1));
            add(new Score("Hálfdan", rnd.nextInt(99) + 1));
            add(new Score("Emmerson", rnd.nextInt(99) + 1));
            add(new Score("Marie", rnd.nextInt(99) + 1));
            add(new Score("Mikha'il", rnd.nextInt(99) + 1));
            add(new Score("Jayanta", rnd.nextInt(99) + 1));
            add(new Score("Theodosia", rnd.nextInt(99) + 1));
            add(new Score("Sharleen", rnd.nextInt(99) + 1));
            add(new Score("Kristian", rnd.nextInt(99) + 1));
            add(new Score("Alberte", rnd.nextInt(99) + 1));
            add(new Score("Maylis", rnd.nextInt(99) + 1));
            add(new Score("Katayun", rnd.nextInt(99) + 1));
        }

        public void save() {
            // Well, because it's nice to remember this stuff
        }

        public void add(Score score) {
            // We could sort the list here, lots of ways to do it ...
            // but waste the time if we don't actually need to
            scores.add(score);
        }

        public List<Score> getScores() {
            // Could use a flag to determine if this actually needs to be
            // sorted or not ... but this is just a demonstration :/
            Collections.sort(scores);
            return Collections.unmodifiableList(scores);
        }

    }

    public class GamePanel extends JPanel {

        private LeaderBoardModel model;
        private Random rnd = new Random();

        public GamePanel(LeaderBoardModel model) {
            this.model = model;

            setLayout(new GridBagLayout());

            JButton btn = new JButton("Win");
            add(btn);
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.add(new Score("l334", rnd.nextInt(99) + 100));
                }
            });
        }

    }

    public class LeaderBoardPanel extends JPanel {

        private LeaderBoardModel model;

        public LeaderBoardPanel(LeaderBoardModel model) {
            this.model = model;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            String highScore = "High Score";

            FontMetrics fm = g2d.getFontMetrics();
            int xPos = (getWidth() - fm.stringWidth(highScore)) / 2;
            int yPos = 10;
            g2d.drawString(highScore, xPos, yPos + fm.getAscent());

            yPos += fm.getHeight() * 2;

            List<Score> scores = model.getScores();
            scores = scores.subList(0, Math.min(10, scores.size() - 1));

            for (Score score : scores) {
                String name = score.getName();
                String value = Integer.toString(score.getScore());

                xPos = (getWidth() / 2) - fm.stringWidth(name) - 5;
                g2d.drawString(name, xPos, yPos + fm.getAscent());
                xPos = (getWidth() / 2) + 5;
                g2d.drawString(value, xPos, yPos + fm.getAscent());

                yPos += fm.getHeight();
            }

            g2d.dispose();
        }

    }
}