Java: Drawing using Graphics outside the class whi

2019-09-17 18:41发布

问题:

I'm trying to develop a Tic Tac Toe game in Java using Graphics. My problem is: I don't want to add any other methods inside my Grid.class (which draws the lines 3x3), but i want to draw my X or O from a class called Game. My grid class looks like the following:

import java.awt.Graphics;
import javax.swing.JPanel;

public class Grid extends JPanel{

    private final int ITEM_WIDTH = 30;
    private final int ITEM_HEIGHT = 30;
    private final int OUTER_WIDTH = 90;
private final int OUTER_HEIGHT = 90;

public void paintComponent(Graphics g){
    super.paintComponent(g);
    drawOuter(g);
    drawGrid(g);
}

public void drawOuter(Graphics g){
    g.drawRect(0, 0, OUTER_WIDTH, OUTER_HEIGHT);
}

public void drawGrid(Graphics g){
    //Vertikális
    for(int i = ITEM_WIDTH; i < OUTER_WIDTH; i += ITEM_WIDTH){
        g.drawLine(i, 0, i, OUTER_HEIGHT);
    }
    //Horizontális
    for(int i = ITEM_HEIGHT; i < OUTER_HEIGHT; i += ITEM_HEIGHT){
        g.drawLine(0, i, OUTER_WIDTH, i);
    }
}

Thank you for your helps

回答1:

My suggestion would be try to keep things as simple as possible.

  • Create ImageIcons that hold your X and O images
  • Have a GridLayout of JLabels placed in your JPanel above.
  • Swapping the JLabel's ImageIcon when I wanted to display an X, an O, or a blank.

Proof of concept code. Clicking on the JLabels several times will show the icons. The code has no Tic-Tac-Toe logic though:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

import javax.swing.*;

@SuppressWarnings("serial")
public class XorOorBlank extends JPanel {
   private static final int IMG_WIDTH = 100;
   private static final Color BACKGROUND = Color.LIGHT_GRAY;
   private static final Color X_COLOR = Color.red;
   private static final Color O_COLOR = Color.blue;
   private static final Stroke X_STROKE = new BasicStroke(8f);
   private static final int GAP = 8;
   private static final int SIDE = 3;
   private Icon blankIcon = createBlankIcon();
   private Icon xIcon = createXIcon();
   private Icon oIcon = createOIcon();

   public XorOorBlank() {
      setBackground(BACKGROUND);
      setLayout(new GridLayout(SIDE, SIDE, GAP, GAP));

      MouseListener mouseListener = new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent e) {
            JLabel label = (JLabel) e.getSource();
            Icon icon = label.getIcon();
            if (icon == blankIcon) {
               icon = xIcon;
            } else if (icon == xIcon) {
               icon = oIcon;
            } else if (icon == oIcon) {
               icon = blankIcon;
            }
            label.setIcon(icon);
         }
      };
      for (int i = 0; i < SIDE; i++) {
         for (int j = 0; j < SIDE; j++) {
            JLabel label = new JLabel(blankIcon);
            label.addMouseListener(mouseListener);
            add(label);
         }
      }
   }

   private Icon createBlankIcon() {
      BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_WIDTH,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setColor(Color.white);
      g2.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
      g2.dispose();
      ImageIcon icon = new ImageIcon(img);
      return icon;
   }

   private Icon createXIcon() {
      BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_WIDTH,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setColor(Color.white);
      g2.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
      g2.setColor(X_COLOR);
      g2.setStroke(X_STROKE);
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      int x1 = GAP;
      int y1 = x1;
      int x2 = IMG_WIDTH - GAP;
      int y2 = x2;
      g2.drawLine(x1, y1, x2, y2);
      g2.drawLine(x2, y1, x1, y2);
      g2.dispose();
      ImageIcon icon = new ImageIcon(img);
      return icon;
   }

   private Icon createOIcon() {
      BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_WIDTH,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setColor(Color.white);
      g2.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
      g2.setColor(O_COLOR);
      g2.setStroke(X_STROKE);
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      int x1 = GAP;
      int y1 = x1;
      int x2 = IMG_WIDTH - 2 * GAP;
      int y2 = x2;
      g2.drawOval(x1, y1, x2, y2);
      g2.dispose();
      ImageIcon icon = new ImageIcon(img);
      return icon;
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("X or O");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new XorOorBlank());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

Note: not a paintComponent method to be found.

This displays:



回答2:

You have a few choices...

You Could

Extend from Grid, overriding it's paintComponent method and draw the X/Os within it (calling super.paintComponent)

You Could

Create a interface which provide a simple "draw" method, which when implemented, would paint either X/O. You could then simply add an new instance of this to the Grid class and have it paint the X/O via some kind of loop within the paintComponent method

You Could

Use, something like GridBagLayout or even OverlayLayout and place another panel over the top of the Grid class, or, using BorderLayout, add the panel directly to the Grid class, which would then be responsible for painting the X/O

You Could

Do what Hovercraft Full Of Eels has suggested...