I have made a game using CardLayout and have one JPanel for the leaderboard. In leaderboard, I read two files (one with names, one with times), sort them and draw the top 5 fastest times like this:
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;
}
}
There is no problem the first time I open the leaderboard. However, if I return to the menu and then come back to the leaderboard, the strings to not draw, but the images do. I also so not get any errors. I can't figure out why this is happening.
How I return to menu:
public void actionPerformed(ActionEvent e) {
if (e.getSource()==back)
RunGame.card.first(RunGame.c);
}
How I go to leaderboard from menu:
else if (e.getSource()==d) //d is a JButton
RunGame.card.show(RunGame.c,"Leaderboard");
I solved my problem. I just had to reset numX nameX timeX lineY each time I switched to leaderboard
Ok, so we've learnt a lesson, global state is a bad thing ...
Ok, since I spent some time putting the example together, I'd post it to demonstrate a basic concept of shared state.
This example creates a LeaderBoardModel
which is shared between the main views. This allows the state to be shared between different aspects of your code, without the need to explicitly understand how it actually works - the model becomes a self contained unit of work and can manage it's own state.
Another aspect here, is trying to keep your paint path as fast as possible - so, even in this example, sorting and splitting the list could be considered for optimisation ... but we're not trying to achieve 200fps ... so, balancing...
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();
}
}
}