Java Swing如何从列表存储展示图形对象 解决绘制消失问题
问题原因
- JFrame默认使用
BorderLayout布局,多次调用add()方法添加组件时,默认都放在BorderLayout.CENTER区域,后添加的组件会覆盖之前的组件,所以只能看到最后一个方格 Field类的ground列表是实例属性,每个Field对象自己持有一个独立的列表,只会存自己的实例,根本收集不到所有9个方格- 职责划分错误,不应该让每个方格自己作为JPanel添加到窗口,应该用一个主面板统一管理所有方格对象、统一执行绘制逻辑
调整后代码
主文件代码
import javax.swing.*; import java.awt.*; import java.util.ArrayList; // 可保留你原来的类名probvam,这里仅做语义化修改 public class TicTacToeMain extends JPanel { // 主面板统一持有所有方格的列表 private ArrayList<Field> ground = new ArrayList<>(); public TicTacToeMain() { int cellSize = 560 / 3; // 批量初始化9个方格 for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { ground.add(new Field(col * cellSize, row * cellSize, cellSize, cellSize)); } } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 必须调用父类方法完成基础绘制,避免内容残留 // 遍历所有方格统一绘制 for (Field f : ground) { g.drawRect(f.x, f.y, f.width, f.height); // 后续需要绘制X/O可以直接在这里扩展逻辑 } } public static void main(String[] args) { // Swing组件初始化放在事件调度线程执行,避免线程安全导致的界面异常 SwingUtilities.invokeLater(() -> { JFrame window = new JFrame(); window.add(new TicTacToeMain()); window.setTitle("zvunqt mi po iphona"); window.setSize(560, 560); window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); window.setVisible(true); }); } }
Field类代码
Field不再需要继承JPanel,改为普通实体类存储方格属性即可:
public class Field { int width, height, x, y; public Field(int x, int y, int w, int h) { this.width = w; this.height = h; this.x = x; this.y = y; } }
后续优化建议
- 若需要处理方格点击事件,可在主面板添加
MouseListener,判断点击坐标落在哪个Field的范围内即可触发对应逻辑 - 后续所有Swing界面的修改、重绘操作都建议放在
SwingUtilities.invokeLater()中执行,避免界面闪烁、绘制异常等问题
内容的提问来源于stack exchange,提问作者Plamen Tsanev
相关产品推荐
相关产品推荐

