正如@camickr 在 cmets 中所写,通常的做法是让板组件绘制其中的内容。
在具有图形用户界面的程序中(以及在其他程序中),您通常应该将您的绘画代码(视图)与您知道什么要绘画的代码(模型)。这个想法被称为Model-View-Controller。
在这里实现 MVC 意味着您的 Board 类应该知道要绘制什么或如何绘制它,但不能同时知道两者。我建议有一个
-
BoardPainter extends JPanel,观点:知道如何自己画东西,对于石头可以去的每个位置都有一个StonePainter(也扩展了JPanel)。它确实不保留关于在哪里绘制什么的信息;相反,它会在每次需要时从MancalaState 询问此信息。当游戏进一步进行时,您还将在此处生成动作:点击源,点击目的地,
-
MancalaState 是模型,它知道每个地方有多少石头,应该由谁移动,决定游戏何时结束,等等。如果您在此处实现toString(),您可以轻松测试整个游戏是否正常运行,无论它是如何绘制的。
要将盆 (StonePainters) 放置在 BoardPainter 中的正确位置,您可以使用现有的 LayoutManager(甚至嵌套 JPanel),编写自己的 LayoutManager,或者直接不使用StonePainter 并直接从您的BoardPainter 在正确位置绘制它们。从我的角度来看,最简单的选择是第一个:
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class Demo {
/** paints a full board */
public static class BoardPainter extends JPanel {
private ArrayList<PotPainter> pots = new ArrayList<>();
private java.util.List<Integer> mancalaBoard; // <-- this would be an actual class
public BoardPainter(java.util.List<Integer> mancalaBoard) {
this.mancalaBoard = mancalaBoard;
setLayout(new BorderLayout());
// a 2x6 grid in the center
JPanel center = new JPanel();
center.setLayout(new GridLayout(2, 6));
for (int i=0; i<12; i++) {
PotPainter p = new PotPainter();
pots.add(p);
center.add(p);
}
add(center, BorderLayout.CENTER);
// one side
PotPainter east = new PotPainter();
pots.add(east);
add(east, BorderLayout.EAST);
east.setPreferredSize(new Dimension(100, 0));
// the other side
PotPainter west = new PotPainter();
pots.add(west);
add(west, BorderLayout.WEST);
west.setPreferredSize(new Dimension(100, 0));
}
public void paint(Graphics g) {
for (int i=0; i<mancalaBoard.size(); i++) {
pots.get(i).setStones(mancalaBoard.get(i));
}
super.paint(g);
}
}
/** paints a pot */
public static class PotPainter extends JPanel {
private static final int MARGIN = 2;
private static final int STONE_SIZE = 10;
private int stones = 0;
public void setStones(int stones) {
this.stones = stones;
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
g.drawOval(MARGIN, MARGIN, getWidth()-MARGIN*2, getHeight()-MARGIN*2);
Random r = new Random();
int d = Math.min(getWidth(), getHeight()) / 2;
Point center = new Point(getWidth()/2, getHeight()/2);
for (int i=0; i<stones; i++) {
g.drawOval(center.x + r.nextInt(d) - d/2, center.y + r.nextInt(d) - d/2,
STONE_SIZE, STONE_SIZE);
}
}
}
public static void main(String ...args) {
SwingUtilities.invokeLater(() -> {
JFrame jf = new JFrame("demo");
jf.add(new BoardPainter(new ArrayList<>(
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 4, 2))));
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(800, 300);
jf.setVisible(true);
});
}
}
样本输出: