You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java开发井字棋:Oval被Rectangle遮挡及对象颜色修改问题

Solution for Your Tic Tac Toe Game Issues

Hey Carter, let's fix those two frustrating issues you're facing with your Tic Tac Toe game—we'll break them down one by one:

1. Fixing the Oval Being Covered by Rectangles

The core problem here is how Swing handles component rendering order when you add multiple elements to a container. If you stick with your current component-based setup, the quick fix is to manually adjust the z-order of your Oval components after adding them to the panel. Swing draws components from the bottom of the stack to the top, so placing your Ovals at the front ensures they render above the Rectangles.

If you want a cleaner, more maintainable solution though, it's better to use a single custom panel to draw both the board and markers. This way you fully control the drawing order: draw the board first, then the markers on top—no more hiding issues.

2. Simplifying Color Modification for Shapes

To easily update the color of your Rectangle and Oval components, add a color setter method to each custom class, paired with an instance variable to store the current color. This lets you change colors on the fly and triggers a repaint to update the visuals immediately.


Quick Fix for Your Existing Code

Adjust Z-Order for Ovals

Update your userInput method to force Ovals to render on top:

static void userInput(){
    int uImpCalc = 1;
    Scanner s = new Scanner(System.in);
    while(uImpCalc <= 9){
        int x = s.nextInt();
        int y = s.nextInt();
        if(x <= 3 && x > 0){
            if(y <= 3 && y >0){
                int rX = (x-1)*80; // Fixed to 0-based index for correct positioning
                int rY = (y-1)*80;
                if(uImpCalc%2 == 0){
                    player1[p1Count][p1Count] = new Oval(rX, rY, 80, 80, Color.BLUE);
                    win.add(player1[p1Count][p1Count]);
                    // Move oval to the front of the rendering stack
                    win.setComponentZOrder(player1[p1Count][p1Count], 0);
                    p1Count++;
                }else{
                    player2[p2Count][p2Count] = new Oval(rX, rY, 80, 80, Color.RED);
                    win.add(player2[p2Count][p2Count]);
                    win.setComponentZOrder(player2[p2Count][p2Count], 0);
                    p2Count++;
                }
                win.repaint();
                System.out.println("Entering '"+x+", "+y+"'");
                uImpCalc++;
            }else{
                System.out.println("Invalid Y: "+y);
            }
        }else{
            System.out.println("Invalid X: "+x);
        }
    }
    System.out.println("Game Over");
    System.exit(0);
}

Add Color Setters to Your Shape Classes

Modify your Rectangle and Oval classes to include these methods (example for Oval):

import javax.swing.*;
import java.awt.*;

public class Oval extends JComponent {
    private Color shapeColor;
    private int x, y, width, height;

    public Oval(int x, int y, int width, int height, Color color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.shapeColor = color;
        setBounds(x, y, width, height);
    }

    // Setter for easy color changes
    public void setShapeColor(Color newColor) {
        this.shapeColor = newColor;
        repaint(); // Refresh the component with the new color
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(shapeColor);
        g.drawOval(5, 5, getWidth()-10, getHeight()-10); // Add padding for better visuals
    }
}

Using a single custom panel to draw everything eliminates z-order issues entirely and simplifies state management. Here's a polished version:

import javax.swing.*;
import java.awt.*;
import java.util.Scanner;

public class GameBoard {
    static JFrame f = new JFrame("Tic Tac Toe");
    static GamePanel gamePanel = new GamePanel();
    
    // Track game state: 0 = empty, 1 = Player 1 (X), 2 = Player 2 (O)
    static int[][] boardState = new int[3][3];

    public static void main(String args[]) {
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(gamePanel);
        f.pack();
        f.setLocationRelativeTo(null); // Center the window
        f.setVisible(true);
        userInput();
    }

    static void userInput() {
        int moveCount = 0;
        Scanner s = new Scanner(System.in);
        while (moveCount < 9) {
            System.out.println("Enter X (1-3) and Y (1-3):");
            int x = s.nextInt() - 1; // Convert to 0-based index
            int y = s.nextInt() - 1;

            if (x >= 0 && x < 3 && y >= 0 && y < 3) {
                if (boardState[y][x] == 0) {
                    boardState[y][x] = (moveCount % 2 == 0) ? 1 : 2;
                    gamePanel.repaint(); // Refresh the board
                    moveCount++;
                    System.out.println("Placed marker at (" + (x+1) + ", " + (y+1) + ")");
                } else {
                    System.out.println("That cell is already taken!");
                }
            } else {
                System.out.println("Invalid coordinates—use 1-3 for both X and Y.");
            }
        }
        System.out.println("Game Over!");
        System.exit(0);
    }

    // Custom panel to draw the entire game
    static class GamePanel extends JPanel {
        private final int CELL_SIZE = 80;
        // Easily modify colors here
        private final Color CELL_COLOR_1 = Color.LIGHT_GRAY;
        private final Color CELL_COLOR_2 = Color.WHITE;
        private final Color PLAYER1_COLOR = Color.BLUE;
        private final Color PLAYER2_COLOR = Color.RED;

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // Draw the board first
            for (int row = 0; row < 3; row++) {
                for (int col = 0; col < 3; col++) {
                    // Alternate cell colors
                    g.setColor((row + col) % 2 == 0 ? CELL_COLOR_1 : CELL_COLOR_2);
                    g.fillRect(col * CELL_SIZE, row * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                    // Draw cell borders
                    g.setColor(Color.BLACK);
                    g.drawRect(col * CELL_SIZE, row * CELL_SIZE, CELL_SIZE - 1, CELL_SIZE - 1);
                }
            }

            // Draw player markers on top
            for (int row = 0; row < 3; row++) {
                for (int col = 0; col < 3; col++) {
                    int player = boardState[row][col];
                    if (player == 1) {
                        // Draw X for Player 1
                        g.setColor(PLAYER1_COLOR);
                        int offset = 10;
                        g.drawLine(col * CELL_SIZE + offset, row * CELL_SIZE + offset,
                                col * CELL_SIZE + CELL_SIZE - offset, row * CELL_SIZE + CELL_SIZE - offset);
                        g.drawLine(col * CELL_SIZE + CELL_SIZE - offset, row * CELL_SIZE + offset,
                                col * CELL_SIZE + offset, row * CELL_SIZE + CELL_SIZE - offset);
                    } else if (player == 2) {
                        // Draw O for Player 2
                        g.setColor(PLAYER2_COLOR);
                        int offset = 10;
                        g.drawOval(col * CELL_SIZE + offset, row * CELL_SIZE + offset,
                                CELL_SIZE - 2 * offset, CELL_SIZE - 2 * offset);
                    }
                }
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(CELL_SIZE * 3, CELL_SIZE * 3);
        }
    }
}

Key Improvements:

  • No more z-order issues: We explicitly draw the board first, then markers on top.
  • Easy color changes: Just update the color constants in GamePanel or add setter methods for dynamic color shifts.
  • Better state management: Uses a simple 2D array to track moves instead of multiple component arrays.
  • Swing-friendly layout: Avoids null layout by using getPreferredSize() for proper window sizing.

内容的提问来源于stack exchange,提问作者Carter Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:20:51