2015-10-13 104 views
1

因此,有一段時間覆蓋JComponent的paint方法給了我麻煩,我永遠不知道爲什麼。我正在研究一個項目,該項目將拍攝黑白圖像並將其繪製在屏幕上,其中畫面中的每個像素都是屏幕上的50 x 50框,顯然有些繪畫將在屏幕外完成,但這是可以的,因爲它將是一個2D移動屏幕的自上而下的遊戲。無論我嘗試過什麼,它在運行時都不會在屏幕上畫任何東西,它與我的1:50邏輯沒有任何關係,因爲當我試圖繪製一個簡單的矩形時,它甚至沒有繪製這個矩形。所以問題必須出現在繪畫方法中,但我無法弄清楚什麼是錯誤的。我知道這是很多代碼,但有人可以讓我知道什麼是錯的? (我知道有很多是沒有被尚未使用方法,只是忽略那些那些)爲什麼我的Paint surface方法不起作用?

這是JFrame類:

(你必須爲黑白圖像的路徑在這個類中繪製)

`package Code; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.awt.RenderingHints; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

//class that stores all of the painting methods and the GUI methods: 
public class Window extends JFrame{ 

    double WINDOWWIDTH, WINDOWHEIGHT; 
    JPanel TitlePanel; 
    JButton PlayGame, Quit; 
    JLabel Title; 
    Map DigitizedMap; 
    PaintSurface PS; 

    int x = 0; 
    int y = 0; 
    int TilesAcross; 
    int TilesDown; 

    public Window(){ 

     WINDOWWIDTH = 1200; 
     WINDOWHEIGHT = (Math.floor(WINDOWWIDTH/50)*0.66) * 50; 
     TilesAcross = (int) (WINDOWWIDTH/50); 
     TilesDown = (int) (WINDOWHEIGHT/50); 

     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setSize((int) WINDOWWIDTH, (int) WINDOWHEIGHT); 
     this.setTitle("Stealth Client || Version 1.0"); 

     //all of the code for the user interface will go here: 
     //DrawStartInterface(this); 

     //creating the digitized verion of the map for the paint method to use: 
     MapLoader ML = new MapLoader("C:\\Users\\Greg\\Desktop\\TestMap.png"); 
     DigitizedMap = ML.ConvertMap(); 
     PS = new PaintSurface(); 
     TitlePanel = new JPanel(); 
     TitlePanel.add(PS, BorderLayout.CENTER); 
     this.add(TitlePanel); 

     this.setVisible(true); 
     this.setResizable(false); 
    } 

    private void DrawStartInterface(JFrame f){ 
     //all of the starting UI: 

     TitlePanel = new JPanel(new GridBagLayout()); 
     TitlePanel.setBackground(Color.DARK_GRAY); 

     Title = new JLabel("STEALTH"); 
     Title.setForeground(Color.ORANGE); 
     Title.setFont(new Font("Calabri", Font.BOLD, 48)); 
     addItem(TitlePanel, Title, 0, 0, 1, 1, 1); 

     PlayGame = new JButton("Play"); 
     PlayGame.setBackground(Color.BLACK); 
     PlayGame.setForeground(Color.ORANGE); 
     PlayGame.setFont(new Font("Calabri", Font.BOLD, 36)); 
     PlayGame.addActionListener(new ActionEvent()); 
     addItem(TitlePanel, PlayGame, 0, 1, 1, 1, 1); 

     Quit = new JButton("Quit"); 
     Quit.setBackground(Color.BLACK); 
     Quit.setForeground(Color.ORANGE); 
     Quit.setFont(new Font("Calabri", Font.BOLD, 36)); 
     Quit.addActionListener(new ActionEvent()); 
     addItem(TitlePanel, Quit, 0, 2, 1, 1, 1); 

     f.add(TitlePanel); 
    } 

    private class ActionEvent implements ActionListener{ 
     @Override 
     public void actionPerformed(java.awt.event.ActionEvent e) { 
      //which action has been heard: 
      if(e.getSource() == PlayGame){ 
       //plays the game: 
       StartGame(); 
      } else if(e.getSource() == Quit){ 
       //Quits the game: 
       Terminate(); 
      } 
     } 

    } 

    public void Terminate(){ 
     //exits the game: 

     System.exit(0); 
    } 

    //Starts the game: 
    private void StartGame(){ 
     TitlePanel.add(PS); 
    } 

    //The paint Surface class that will be stored in the panel and paint the game: 
    class PaintSurface extends JComponent{ 
     @Override 
     public void paint (Graphics g){ 
      //basic graphics shizel wizel: 
      Graphics2D g2 = (Graphics2D) g; 
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
        RenderingHints.VALUE_ANTIALIAS_ON); 
      g2.drawRect(100, 100, 100, 100); 
      render(g2); 
      System.out.println("Painted"); 
     } 

     private void render(Graphics2D g2){ 
      //renders only the squares within a certain distance of the center of the screen: 
      int PlayerTileX = (int) Math.ceil((x + (WINDOWWIDTH/2))/50);  // This is the x tile that the player is in 
      int PlayerTileY = (int) Math.ceil((y + (WINDOWHEIGHT/2))/50);  // this is the y tile that the player is in 
      //now we are going through only the tiles around the player and rendering them: 
      int XOffset = x - (int) (PlayerTileX - (Math.ceil(TilesAcross/2))); 
      int YOffset = y - (int) (PlayerTileY - (Math.ceil(TilesDown/2))); 
      for (int i = (int) (PlayerTileX - (Math.ceil(TilesAcross/2))); i < (int) (PlayerTileX + (Math.ceil(TilesAcross/2))); i++){ 
       for (int n = (int) (PlayerTileY - (Math.ceil(TilesDown/2))); n < (int) (PlayerTileY + (Math.ceil(TilesDown/2))); n++){ 
        //this is where only the coorect boxes will be rendered because of the limiting for loops: 
        //The if statement for determining what type of thing it is: 
        if (DigitizedMap.getTile(i, n) == 1){ 
         //Rendering the walls: 
         g2.drawRect((int)(((i * 50) % WINDOWWIDTH) - XOffset), (int)(((i * 50) % WINDOWHEIGHT) - YOffset), 50, 50); 
        } 
       } 
      } 
     } 
    } 

    //used to add things to panels: 
    public void addItem(JPanel p, JComponent c, int x, int y, int width, int height, 
      int align /* Defines the spot on the coordinate */) { 
     GridBagConstraints gc = new GridBagConstraints(); 
     gc.gridx = x; 
     gc.gridy = y; 
     gc.gridwidth = width; 
     gc.gridheight = height; 
     gc.insets = new Insets(10, 10, 10, 10); 

     switch (align) { 
     case 1: 
      gc.anchor = GridBagConstraints.NORTH; 
      break; 
     case 2: 
      gc.anchor = GridBagConstraints.EAST; 
      break; 
     case 3: 
      gc.anchor = GridBagConstraints.SOUTH; 
      break; 
     case 4: 
      gc.anchor = GridBagConstraints.WEST; 
      break; 
     case 5: 
      gc.anchor = GridBagConstraints.CENTER; 
      break; 
     } 
     p.add(c, gc); 
    } 

} 
` 

這裏是Starthere類(類,它包含的主要方法):

package Code; 

public class StartHere { 
    public static void main(String[] args) { 
     //Creating the frame: 
     final Window Frame = new Window(); 
    } 

} 

這裏是地圖類存儲所有O F中的地圖數據:

package Code; 

public class Map { 

    //the Array for all of the codes: 
    double Tiles[][]; 
    int width; 
    int height; 

    //setters and getters for the width and height: 
    public int getWidth() { 
     return width; 
    } 

    public void setWidth(int width) { 
     this.width = width; 
    } 

    public int getHeight() { 
     return height; 
    } 

    public void setHeight(int height) { 
     this.height = height; 
    } 


    //the constructor for the double map: 
    public Map(long Width, long Height){ 
     Tiles = new double[(int) Width][(int) Height]; 
    } 

    //this is where the double array is going to be set: 
    public void setTile(int x, int y, double type){ 
     Tiles[x][y] = type; 
    } 

    //this gets the given tile code: 
    public double getTile(int x, int y){ 
     return Tiles[x][y]; 
    } 

} 

最後,這裏是地圖加載器類,它負責從圖像文件加載地圖:

package Code; 

import java.awt.Color; 
import java.awt.Image; 
import java.awt.image.BufferedImage; 
import java.awt.image.ImageObserver; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 

public class MapLoader { 

    BufferedImage MapImage; 

    public MapLoader(String MapPath){ 
     //loading the map image from the specified map path: 
     try { 
      MapImage = ImageIO.read(new File(MapPath)); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
    public Map ConvertMap(){ 
     Map m = new Map(MapImage.getWidth(), MapImage.getHeight()); 

     //now to read the individual pixels of the image and determine the code for the map object: 
     for(int i = 0; i < MapImage.getWidth(); i++){ 
      for(int n = 0; n < MapImage.getHeight(); n++){ 
       if (MapImage.getRGB(i, n) == Color.BLACK.getRGB()){ 
        //Black = Wall = 1 
        m.setTile(i, n, 1); 
        System.out.print("1"); 
       } else { 
        //else it is nothing so White = Space = 0 
        m.setTile(i, n, 0); 
        System.out.print("0"); 
       } 
      } 
      System.out.println(""); 
     } 

     return m; 
    } 

} 

謝謝你這麼多的人,幫助這有一直困擾着我好幾天,而且我沒有想法。

而且,這裏是我一直在使用一個例子文件: Example File

+0

1)總是重寫paintComponent,而不是繪畫。任何體面的圖形教程都會告訴你這一點。 2)如果你重寫了,在你的覆蓋範圍內,總是調用super的繪畫方法'super.paintComponent(...)'。 3)以這樣的方式創建你的代碼,以便每個類都可以獨立測試和調試,使用小模擬類來幫助你做到這一點。 4)通過這種方式,如果遇到錯誤,您可以創建併發布您的[mcve]供我們測試,而不是要求我們瀏覽整個大型程序。 –

+0

請注意,您從不**調用'DrawStartInterface(...)'!支持建議:請學習並遵循Java命名約定,因爲這樣做可以幫助他人更好地理解您的代碼。 –

回答

3

你的paint方法的工作原理,但沒有人能看到PaintSurface對象。您有:

PS = new PaintSurface(); 
    TitlePanel = new JPanel(); 
    TitlePanel.add(PS, BorderLayout.CENTER); 

你加入PS對象到BorderLayout.CENTER位置,但TitlePanel不使用BorderLayout的 - 它使用默認的FlowLayout。現在PaintSurface具有0,0的首選大小,並且由於TitlePanel使用FlowLayout,所以PS將會是非常小的

解決方案:將TitlePanel的佈局設置爲BorderLayout。

PS = new PaintSurface(); 
    TitlePanel = new JPanel(new BorderLayout()); 
    TitlePanel.add(PS, BorderLayout.CENTER); 

這將使PaintSurface實例填充TitlePanel。


另外,按我的意見:

  • 始終重寫paintComponent,不畫。任何體面的圖形教程都會告訴你這一點。
  • 如果您在覆蓋範圍內覆蓋該方法,請始終調用super的繪畫方法super.paintComponent(...)。
  • 以這樣的方式創建您的代碼,以便每個類都可以獨立測試和調試,使用小模擬類來幫助您完成此操作。
  • 這樣,如果遇到錯誤,您可以創建併發布您的最小化,完整和可驗證示例,供我們測試,而不是要求我們瀏覽整個大型程序。
  • 請注意,您從不打電話DrawStartInterface(...)
  • 請學習並遵循Java命名約定,因爲這樣做可以幫助他人更好地理解您的代碼。字段和方法名稱都應以小寫字母開頭,而類和接口名稱應以大寫字母開頭。
+0

僅供參考,Java命名約定:http://www.oracle.com/technetwork/java/codeconventions-150003.pdf – VGR

+0

另外,不要將您的類命名爲「Window」,因爲您最終會與java混淆。 AWT.Window類,它是JFrame的超類。對於這個問題,儘量不要將你的類命名爲與現有Java類相同的類。 – FredK

相關問題