簡體   English   中英

如何將另一個類中的對象傳遞給paintComponent方法?

[英]How do I pass an object from another class into the paintComponent method?

我的任務是創建游戲“ FloodIt”。 如果您需要了解游戲,可以在這里玩,但我認為這不是真正必要的: http : //unixpapa.com/floodit/

我已經完成了游戲的實際部分,但是現在我需要為其制作圖形界面。 我有三節課:

Board.java,它使板子具有隨機的int值,並包含其他幾種使游戲正常工作的方法:

import java.awt.Color;
import java.util.Random;


/**The board class for the Flood-It game.  This class implements a NxN board filled with numColors colors.
 * The class implements several methods to allow the playing of the game.
 */

class Board {

//you will probably need to create some field variables
private int size;
private int numColors;
private int[][] board;
private int numOfMoves;
/**Constructs a new sizeXsize board filled where each element on the board is a random number between 0
 * and numColors.  Also initializes the number of moves to zero.
 * @param size -- the size of the board
 * @param numColors -- the number of possible entries on the board
 */
public Board(int size,int numColors) {
    //TODO finish this constructor
    this.size = size;
    this.numColors = numColors;
    numOfMoves = 0;



    board = new int[size][size];
    Random rand = new Random();
    int randomNum = 0;
    for (int count = 0; count < size; count++) {
        for (int counter = 0; counter < size; counter++) {
            randomNum = rand.nextInt(this.numColors);
            board[count][counter] = randomNum;
        }
    }


}


/**Updates the board to fill (from the top left corner) with a specified color.  
 * Filling stops when any other color is hit besides the one in the top left corner.
 * Play the game at http://www.lemoda.net/javascript/flood-it/ or http://unixpapa.com/floodit/?sz=14&nc=4
 * to get a better understanding of what this method should do.
 * You will probably also want to take a look at the algorithm described
 * at http://en.wikipedia.org/wiki/Flood_fill which describes what this method should do.
 * I recommend the Stack-based recursive implementation.  It is a recursive algorithm for
 * flooding the board.  It is one of the easier ones to implement.
 * You are free to have this method call other methods.  I would recommend creating a private method that
 * this method calls and have that private method be the recursive method.
 * A recursive method is one that calls itself.
 * @param color -- the new color to flood the board with.
 */
public void move(int replacementColor) {
    int targetColor = board[0][0];
    recursiveMove(0,0,targetColor,replacementColor);
    numOfMoves++;
}

private void recursiveMove(int xCoord, int yCoord, int targetColor, int replacementColor) {
    if (targetColor == replacementColor) {
        return;
    }
    if (board[xCoord][yCoord] != targetColor) {
        return;
    }

    board[xCoord][yCoord] = replacementColor;
    if (yCoord != size-1) {
        recursiveMove(xCoord,yCoord+1,targetColor,replacementColor);
    }
    if (yCoord != 0) {
        recursiveMove(xCoord,yCoord-1,targetColor,replacementColor);
    }
    if (xCoord != 0) {
        recursiveMove(xCoord-1,yCoord,targetColor,replacementColor);
    }
    if (xCoord != size-1) {
        recursiveMove(xCoord+1,yCoord,targetColor,replacementColor);
    }
}


/**returns true if the board is not completely filled with a single color.
 * Otherwise it returns false.
 * @return true if board is all one color
 */
public boolean finished() {
    //TODO finish this method
    for (int count = 0; count < size; count++) {
        for (int counter = 0; counter < size; counter++) {
            if (board[count][counter] != board[0][0]) {
                return false;
            }
        }
    }
    return true;
}


/**returns how many times the move() method has been called.
 * @return the number of times the move() method has been called.
 */
public int numMoves() {
    //TODO finish this method
    return numOfMoves;
}


/**Returns a string representation of the board.  Use tabs between elements of the board.
 * And have every row of the board be separated by a newline character.
 * Example:
 * "1\t0\t3\t\n2\t0\t2\t\n1\t0\t1\t\n"
 * @return a String representation of the board
 */
public String toString() {
    //TODO finish this method
    String boardString = "";
    for (int count = 0; count < board.length; count++) {
        for (int counter = 0; counter < board.length; counter++) {
            boardString += board[count][counter];
            boardString += "\t";
        }
        boardString += "\n";
    }
    return boardString;
}
}

FloodIt.java,其中包含用於加載圖形界面的JFrame行,以及用於實際運行游戲的代碼(由於卡住,它還沒有完全完成):

import java.util.Scanner;
import javax.swing.JFrame;

/**This class is the main method for the Flood-It game as found on many web sites 
 * ( such as http://www.lemoda.net/javascript/flood-it/ or 
http://unixpapa.com/floodit/?sz=14&nc=4 ).
 * It prompts the user for the size of the board
 * and the number of colors.  The user is prompted for the next color until the board is flooded.
 * After the game is over it prints how many turns the user took and then asks if they want to play again.
 */
class FloodIt {

private static final int FRAMESIZE = 1000;

public static void main(String args[]) {
    JFrame frame = new JFrame();
    frame.setSize(FRAMESIZE,FRAMESIZE);
    frame.setTitle("Brennan's Game");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    GraphicalBoard component = new GraphicalBoard();
    frame.add(component);
    frame.setVisible(true);

    String again="";
    int size = 20;
    int numColors = 7;
    do {
        Board board=new Board(size,numColors);
        while(!board.finished()) {
            //I will change the print statements below into graphical input boxes later
            System.out.print("****************\n"+board+"\n****************\n");
            System.out.print("What color do you choose? ");
            int color=Integer.parseInt(scan.nextLine());
            board.move(color);
        }
        System.out.println("Nice job, you finished in "+board.numMoves());
        System.out.print("Would you like to play again (Y/N)? ");
        again=scan.nextLine();
    } while (again.equalsIgnoreCase("Y"));
    scan.close();
}
}

還有GraphicalBoard.java,應該從Board.java獲取2d數組的值,並在圖形界面中顯示板。 2d數組中可能存在的每個數字都與Colors數組中的顏色相對應:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;

public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
public void paintComponent(Graphics g, int size, Board board) {
    String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
    Graphics2D g2 = (Graphics2D) g;
    int xCoord = 0;
    int yCoord = 0;
    int colorNum = 0;
    String colorOfSquare = "";
    for (int count = 0; count < size; count++) {
        for (int counter = 0; counter < size; counter++) {
            colorNum = board[count][counter];
            colorOfSquare = colors[colorNum];
            g2.setColor(Color.colorOfSquare);
            Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
            xCoord += 50;
        }
        yCoord += 50;
    }
}

}

兩個問題:

  1. 在GraphicalBoard.java中,在“ colorNum = board [count] [counter];”行上,出現錯誤:“表達式的類型必須是數組類型,但必須解析為Board。”

我似乎在將已經初始化的板從Board.java類轉移到GraphicalBoard.java類時遇到問題。

  1. 在GraphicalBoard.java中,在“ g2.setColor(Color.colorOfSquare);”行中,出現錯誤:“ colorOfSquare無法解析或它不是字段。”

我知道問題所在,應該是“ g2.setColor(Color.BLACK);”之類的東西,但是我要讓用戶輸入顏色,因此它需要是一個變量,我希望除了每種顏色的if語句外,還有其他更干凈的東西。

有什么建議么? 謝謝!

  1. 您的Board類包含一個成員變量int[][] board ,但是它的作用域是私有的。 當您致電以下內容:

    colorNum = board [count] [counter];

這是錯誤的,因為此處的board變量是Board類的對象。 它本身不是兩天的數組,但是將int[][] board封裝在其中。 因此,您需要在Board提供一個getter方法來公開其board成員變量,如下所示:

public int[][] getBoard() {
  return board;
} 

然后,在paintComponent方法中,您可以通過以下方式訪問它: board.getBoard()[count][counter]

  1. 您似乎已經在colorOfSquare變量中已經有用戶輸入了顏色。 但是Graphics2DsetColor方法將只接受類型為java.awt.Color的變量。 既然你有顏色的字符串表示,可以提到使用反射得到其相應的價值java.awt.Color中這里 以下應該為您工作:

     Color color; try { Field field = Color.class.getField(colorOfSquare); color = (Color) field.get(null); } catch (Exception e) { color = null; // Not defined } 

兩個答案:

  1. paintComponent 接收Graphics對象。 請參閱此鏈接以獲取簡短教程。 如果您需要使用此方法訪問其他對象,請將它們設置為GraphicalBoard變量,並在構造過程中將其傳遞給om。

1.5您需要訪問董事會的董事會,因為這是您正在使用的。 因此getBoard(int i, int j)在類Board添加一個getBoard(int i, int j) 類似於以下內容(我還添加了getSize()方法):

public int getBoard(int i, int j) {
  return board[i][j] ;
} 

public int getSize() {
   return size;
} 
  1. 您的顏色colorOfSquare已定義為一種顏色。 由於Color類沒有這樣的常數而產生錯誤。 您應該直接傳遞顏色。

嘗試這個:

  public class GraphicalBoard extends JComponent { 

     private int xSize = 50; 
     private int ySize = 50; 
     private Board board;
     private int size;

      public GraphicalBoard() {
       } 

      public void setBoard(Board board){
         this.board = board;
     } 

      public void paintComponent(Graphics g) { 
        super.paintComponent(); 

        if(board == null) {
          throw new RuntimeException("Board not set") ;
       } 

         String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"}; 
         Graphics2D g2 = (Graphics2D) g; 
         int xCoord = 0; 
         int yCoord = 0; 
         int colorNum = 0; 
         int size = board.getSize() ;
        String colorOfSquare = ""; 

        for (int count = 0; count < size; count++) { 

            for (int counter = 0; counter < size; counter++) { 
               colorNum = board.getBoard(count, counter) ; 
               colorOfSquare = colors[colorNum]; 
               g2.setColor(colorOfSquare); 
               Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize); 
               xCoord += 50; 
             } 
           yCoord += 50;
         } 
}

總的來說,

  1. 您的視圖(這里的圖形JPanel)應包含通過has-a或“ composition”結構對模型對象的引用
  2. 應該經常通過事件偵聽器(例如PropertyChangeListener)將模型中的更改通知給視圖
  3. 然后,視圖提取關鍵信息,並使用該信息來幫助確定要繪制的內容。 因此,如果它具有對當前Board對象的引用,則可以從paintComponent方法內部進行getter方法調用。

您代碼中的其他問題:

  • 確保在您的覆蓋范圍內調用上級的paintComponent,否則您將不會清理“臟”像素
  • 請勿將線性代碼與基於System.in的掃描儀與GUI代碼混合使用。 做到這一個或另一個。

例如,在下面的代碼中,我使用一個模型類,該類包含int [] []板變量,在這里稱為BoardModel,並給它一個SwingPropertyChangeSupport對象。

class BoardModel {
    // .....
    private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);

該對象將接受偵聽器,並允許我將模型更改通知偵聽器。

public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
    support.addPropertyChangeListener(propertyName, listener);
}

然后,當模型更改時,我通過調用支持對象的firePropertyChange(...)方法來通知所有偵聽器:

public void selectSquare(int x, int y) {
    int replacementValue = board[y][x];
    int targetValue = board[0][0];
    if (targetValue == replacementValue) {
        return;
    } else {
        recursiveMove(0, 0, targetValue, replacementValue);
        numOfMoves++;
        support.firePropertyChange(BOARD, null, board);  // ***** here
        setWin(checkForWin());
    }
}    

然后在控件中,我可以添加偵聽器,以通知更改的視圖:

       model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                view.repaint();
                String moveCount = "" + model.getNumOfMoves();
                controlPanel.setMoveCountFieldText(moveCount);
            }
        });
        model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ((boolean) evt.getNewValue()) {
                    String message = "Move count: " + model.getNumOfMoves();
                    String title = "Game Over";
                    int messageType = JOptionPane.PLAIN_MESSAGE;
                    JOptionPane.showMessageDialog(view, message, title, messageType);
                }
            }
        });

一個可行的示例如下所示:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.SwingPropertyChangeSupport;

public class BoardFun {
    private static final int NUM_COLORS = 6;
    private static final int SIZE = 20;

    @SuppressWarnings("serial")
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            int size = SIZE;
            int numColors = NUM_COLORS;
            final BoardModel model = new BoardModel(size , numColors );
            final BoardPanel view = new BoardPanel();
            final ControlPanel controlPanel = new ControlPanel();

            view.setModel(model);
            view.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent mEvt) {
                    Point p = mEvt.getPoint();
                    int row = view.getRow(p);
                    int col = view.getColumn(p);
                    model.selectSquare(col, row);
                }
            });
            model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent e) {
                    view.repaint();
                    String moveCount = "" + model.getNumOfMoves();
                    controlPanel.setMoveCountFieldText(moveCount);
                }
            });
            model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if ((boolean) evt.getNewValue()) {
                        String message = "Move count: " + model.getNumOfMoves();
                        String title = "Game Over";
                        int messageType = JOptionPane.PLAIN_MESSAGE;
                        JOptionPane.showMessageDialog(view, message, title, messageType);
                    }
                }
            });
            controlPanel.setResetAction(new AbstractAction("Reset") {

                @Override
                public void actionPerformed(ActionEvent e) {
                    model.reset();
                }
            });

            JFrame frame = new JFrame("Game");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(view);
            frame.add(controlPanel, BorderLayout.PAGE_START);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

@SuppressWarnings("serial")
class ControlPanel extends JPanel {
    private JTextField moveCountField = new JTextField("0", 10);
    private JButton resetButton = new JButton();

    public ControlPanel() {
        add(new JLabel("Move Count:"));
        add(moveCountField);
        add(resetButton);
    }

    public void setResetAction(Action action) {
        resetButton.setAction(action);
    }

    public void setMoveCountFieldText(String text) {
        moveCountField.setText(text);
    }
}

@SuppressWarnings("serial")
class BoardPanel extends JPanel {
    private static final int PREF_W = 640;
    private static final int PREF_H = PREF_W;
    private BoardModel model;
    private Color[] colors;

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        } else {
            return new Dimension(PREF_W, PREF_H);
        }
    }

    public void setModel(BoardModel model) {
        this.model = model;
        colors = new Color[model.getNumColors()];

        // create colors.length Colors, all of different hue
        for (int i = 0; i < colors.length; i++) {
            float hue = (float) i / colors.length;
            colors[i] = Color.getHSBColor(hue, 1f, 1f);
        }
    }

    // translate point to logical square position
    int getRow(Point p) {
        return (p.y * model.getBoard().length) / getHeight();
    }

    int getColumn(Point p) {
        return (p.x * model.getBoard()[0].length) / getWidth();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);  // always call the super's method
        if (model == null) {
            return;
        }
        int board[][] = model.getBoard();
        int height = getHeight() / board.length;
        int width = getWidth() / board[0].length;
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                Color color = colors[board[i][j]];
                g.setColor(color);
                int x = (j * getWidth()) / board[0].length;
                int y = (i * getHeight()) / board.length;
                g.fillRect(x, y, width, height);
            }
        }
    }
}

class BoardModel {
    public static final String BOARD = "board";
    public static final String WIN = "win";
    private int[][] board;
    private int numColors;
    private Random random = new Random();
    private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
    private int numOfMoves = 0;
    private boolean win = false;

    public BoardModel(int size, int numColors) {
        board = new int[size][size];
        this.numColors = numColors;
        reset();
    }

    public void reset() {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                board[i][j] = random.nextInt(numColors);
            }
        }
        numOfMoves = 0;
        support.firePropertyChange(BOARD, null, board);
        setWin(false);
    }

    public int[][] getBoard() {
        return board;
    }

    public int getNumOfMoves() {
        return numOfMoves;
    }

    public int getNumColors() {
        return numColors;
    }

    public void setWin(boolean win) {
        boolean oldValue = this.win;
        boolean newValue = win;
        this.win = win;
        support.firePropertyChange(WIN, oldValue, newValue);
    }

    public boolean isWin() {
        return win;
    }

    public void selectSquare(int x, int y) {
        int replacementValue = board[y][x];
        int targetValue = board[0][0];
        if (targetValue == replacementValue) {
            return;
        } else {
            recursiveMove(0, 0, targetValue, replacementValue);
            numOfMoves++;
            support.firePropertyChange(BOARD, null, board);
            setWin(checkForWin());
        }
    }



    public boolean checkForWin() {
        int value = board[0][0];
        for (int[] row : board) {
            for (int cell : row) {
                if (cell != value) {
                    return false;
                }
            }
        }
        return true;
    }

    private void recursiveMove(int i, int j, int targetValue, int replacementValue) {
        int currentValue = board[i][j];
        if (currentValue != targetValue || currentValue == replacementValue) {
            return;
        }
        board[i][j] = replacementValue;
        int rowMin = Math.max(0, i - 1);
        int rowMax = Math.min(board.length - 1, i + 1);
        int colMin = Math.max(0, j - 1);
        int colMax = Math.min(board[i].length - 1, j + 1);
        for (int i2 = rowMin; i2 <= rowMax; i2++) {
            if (i2 != i) {
                recursiveMove(i2, j, targetValue, replacementValue);
            }
        }
        for (int j2 = colMin; j2 <= colMax; j2++) {
            if (j2 != j) {
                recursiveMove(i, j2, targetValue, replacementValue);
            }
        }
    }

    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        support.addPropertyChangeListener(propertyName, listener);
    }   
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM