2017-04-03 41 views
1

Frame - >MainContentPane - >MapPanel - >Map - >Tile[]JPanel JComponents不重繪,除非JFrame.validate();添加組件到visable幀之後被稱爲

JFrame - >JPanel(new GridBagLayout) - >JPanel - >JPanel(new GridLayout(31,30) - >JComponent

我想在JPanel上繪製32x32像素圖塊,但無論我在哪裏調用repaint();如果我調用validate(),它將只繪製圖塊。在JFrame上。 如果我忽略面板並直接使用(使用draw()方法)到MapPanel上,則只有在調整大小或移動JFrame以使幀必須由repaintmanager重新繪製時,圖像纔會繪製。然而,在我的ContentPanel上調用repaint(),validate()或兩者都不會繪製圖像。

如果我理解Java.swing如何繪製正確的東西,如果我在最高級別組件上調用repaint,則應重新繪製repaintmanager認爲應重新繪製的所有子組件。由於我在框架設置爲可見之後添加組件,因此我需要在最高級別Component上調用validate()以告知repaintmanager有新事物。我對這種理解是否正確?

的事情,是行不通的:

告訴我的框架設置爲可見之前所有的組件添加。 MapTile[]將會相當有規律地進行更改,每次添加/刪除內容時重置幀都是非常不切實際的。

public class NetScore { 

    public static void main(String[] args) { 
     MapPanel mapPanel = new MapPanel(); 
     InfoPanel infoPanel = new InfoPanel(); 
     ImageLoader imageLoader = new ImageLoader(); 

     Player player = new Player("Tester", imageLoader); 

     JPanel contentPane = new MainContentPane((JPanel)mapPanel, (JPanel)infoPanel); 

     System.out.println(mapPanel.getHeight()); 
     System.out.println(mapPanel.getWidth()); 

     MapBuilder mapBuilder = new MapBuilder(player, imageLoader); 

     Map map = new Map(mapBuilder, mapPanel, player); 
     map.drawMap(); 

     System.out.println(); 
    } 

    } 
public class MapPanel extends JPanel implements ActionListener{ 

    Map map; 
    Timer clock; 
    public MapPanel(){ 
     clock = new Timer(500, this); 
     clock.start(); 

    } 

    public void addMap(Map map){ 
     this.map = map; 
     this.add(map); 
     this.validate(); 
    } 

    public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     System.out.println(map == null); 
     System.out.println("paint mapPanel"); 
     Graphics2D g2 = (Graphics2D) g; 
     if(map == null){ 
      //map.draw(g2); 
     } 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     //repaint(); 

    } 
    } 
public class MainContentPane extends JPanel implements ActionListener{ 

    public JFrame frame; 
    Timer clock; 

    public MainContentPane(JPanel mapPanel ,JPanel infoPanel){ 
     clock = new Timer(500, this); 
     clock.start(); 
     frame = new Frame(); 
     JPanel contentPane = new JPanel(); 
     frame.setContentPane(contentPane); 
     contentPane.setLayout(new GridBagLayout()); 
     GridBagConstraints c = new GridBagConstraints(); 

     c.weightx = 2; 
     c.gridx = 0; 
     c.gridy = 0; 
     c.fill = GridBagConstraints.BOTH; 
     contentPane.add(mapPanel, c); 

     c.weightx = 1; 
     c.weighty = 1; 
     c.gridx = 1; 
     c.gridy = 0; 
     c.fill = GridBagConstraints.BOTH; 


     contentPane.add(infoPanel, c); 
     frame.setVisible(true); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     repaint(); 

    } 

    class Frame extends JFrame{ 

     public Frame(){ 
      this.setTitle("netScore"); 
      this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
      this.setBounds(100, 10, 1500, 1000); 
      this.setResizable(false); 
     } 

    } 
    } 
public class Map extends JPanel{ 


    private Tile[][] tiles; 
    private MapBuilder mapBuilder; 
    private Player player; 


    public Map(MapBuilder mapBuilder, MapPanel mapPanel, Player player){ 
     this.player = player; 
     this.mapBuilder = mapBuilder; 
     this.setLayout(new GridLayout(31,30)); 
     mapPanel.addMap(this); 
    } 

    public void loadMap(){ 
     tiles = mapBuilder.buildMap(); 
    } 

    public void drawMap(){ 
     loadMap(); 
     this.removeAll(); 
     for(int i = 0; i < tiles.length; i++){ 
      for(int p = 0; p < tiles[i].length; p++){ 
       this.add(tiles[i][p]); 
      } 
     } 
     validate(); 
    } 
    public void draw(Graphics2D g2){ 
     if(tiles != null){ 
      for(int i = 0; i < tiles.length; i++){ 
       for(int p = 0; p <tiles[i].length; p++){ 
        tiles[i][p].draw(g2, i*32, p*32); 
       } 
      } 
     } 
    } 

     // private class GlassPanel extends JComponent{ 
     //   
     //   
     //  @Override 
     //  protected void paintComponent(Graphics g) { 
     //   super.paintComponent(g); 
     //   Graphics2D g2 = (Graphics2D) g; 
     //   g2.drawImage(player.getImage(), player.getX(), player.getY(), null); 
     //    
     //  } 
     //   
     // } 
     } 
public class Tile extends JComponent{ 

    private int id; 
    private boolean collision; 
    private BufferedImage image; 

    public Tile(char diCo, int id, ImageLoader imageLoader){ 
     this.id = id; 

     collision = (Character.isUpperCase(diCo)); 
     image = imageLoader.getTileImage(id, diCo); 
     setPreferredSize(new Dimension(32, 32)); 
    } 

    // public Dimension getPreferredSize(){ 
    //  return new Dimension(32,32); 
    // } 

    public boolean isCollision() { 
     return collision; 
    } 

    public void draw(Graphics2D g2, int x, int y){ 
     System.out.println("paint tile, id "+ id); 
     g2.drawImage(image, null, x, y); 
    } 

    public void paintComponent(Graphics g){ 
     System.out.println("paint tile, id "+ id); 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D) g; 
     g2.drawImage(image, null, 0, 0); 
    } 
} 

編輯:添加了最少的代碼。 這將工作,如果我替換validate();與revalidate();但我不想使用revalidate();如果專家組沒有任何內容需要被撤銷。我是否願意這樣想?

public class test { 
    public static void main(String[] args) throws Exception { 

    MapPanel mapPanel = new MapPanel(); 
    ContentPanel contentPanel = new ContentPanel((JPanel)mapPanel); 
    Map map = new Map(); 
    mapPanel.add(map); 
    map.loadMap(); 

    } 
} 
class MapPanel extends JPanel{ 
    public MapPanel(){ 
    //this.setBackground(Color.BLACK); 

    } 
} 

class Map extends JPanel{ 
    BufferedImage image; 
    public Map(){ 
     try { 
      image = ImageIO.read(new File("graphics//brick_brown0.png")); 
     } catch (IOException e) { 
      System.err.println("can't find file."); 
     } 
    setLayout(new GridLayout(31,30)); 
    setPreferredSize(new Dimension(962,992)); 
} 
public void loadMap(){ 
    for(int i = 0; i < 30; i++){ 
     for(int p = 0; p < 31; p++){ 
      add(new Tile(image)); 
     } 
    } 
    validate(); 
} 
} 

class Tile extends JComponent{ 

BufferedImage image; 
public Tile(BufferedImage image){ 
    this.image = image; 
    setPreferredSize(new Dimension(32,32)); 
} 

public void paintComponent(Graphics g){ 
    super.paintComponent(g); 
    Graphics2D g2 = (Graphics2D) g; 
    g2.drawImage(image, null, null); 
} 
} 


class ContentPanel extends JPanel implements ActionListener{ 
Timer clock = new Timer(100, this); 

public ContentPanel(JPanel mapPanel){ 
    clock.start(); 
    setLayout(new BorderLayout()); 
    JFrame frame = new Frame(); 
    frame.setContentPane(this); 
    add(mapPanel); 
    frame.setVisible(true); 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    repaint(); 
} 

private class Frame extends JFrame{ 
    public Frame(){ 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setBounds(100, 100, 1000, 1000); 
    } 
} 
} 
+1

可以踩上下左右中所示的窗口後添加的東西,不過比較遺憾的搖擺是不會這樣的。如果要在顯示對話框後修改對話框,您必須在事件分派線程上執行此操作,這意味着您必須使用SwingUtilities.invokeLater或使用SwingWorker。 – MeBigFatGuy

+1

1)爲了更快地獲得更好的幫助,請發佈[MCVE]或[簡短,獨立,正確的示例](http://www.sscce.org/)。 2)獲取圖像的一種方法是通過[本問答](http://stackoverflow.com/q/19209650/418556)中的圖像進行熱鏈接。 –

+0

@Andrew Thompson這是一個最小版本,我沒有問題的圖像,但JComponents的繪畫。 – Spik330

回答

1

與代碼發佈的基本問題是,JFrame正在設置可見之前被添加的組件。儘管在頂層容器變得可見之後,添加組件並使它們可見的方法有多種,但在這種情況下似乎沒有必要。

這是一個工作版本,它使用在運行時生成的圖像,在GridLayout中用一點空格來表示網格是31 x 30個組件。

enter image description here

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

public class TestRepaint { 

    public static void main(String[] args) throws Exception { 

     MapPanel mapPanel = new MapPanel(); 
     Map map = new Map(); 
     mapPanel.add(map); 
     map.loadMap(); 
     new ContentPanel((JPanel) mapPanel); 
    } 
} 

class MapPanel extends JPanel { 

    public MapPanel() { 
     this.setBackground(Color.RED); 
    } 
} 

class Map extends JPanel { 

    BufferedImage image; 

    public Map() { 
     image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_BGR); 
     setLayout(new GridLayout(31, 30,2,2)); 
     //setPreferredSize(new Dimension(962, 992)); 
    } 

    public void loadMap() { 
     for (int i = 0; i < 30; i++) { 
      for (int p = 0; p < 31; p++) { 
       add(new Tile(image)); 
      } 
     } 
     validate(); 
    } 
} 

class Tile extends JComponent { 

    BufferedImage image; 

    public Tile(BufferedImage image) { 
     this.image = image; 
     setPreferredSize(new Dimension(image.getWidth(), image.getHeight())); 
    } 

    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D) g; 
     g2.drawImage(image, null, null); 
    } 
} 

class ContentPanel extends JPanel implements ActionListener { 

    Timer clock = new Timer(100, this); 

    public ContentPanel(JPanel mapPanel) { 
     clock.start(); 
     setLayout(new BorderLayout()); 
     JFrame frame = new Frame(); 
     frame.setContentPane(this); 
     add(mapPanel); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     repaint(); 
    } 

    private class Frame extends JFrame { 

     public Frame() { 
      setDefaultCloseOperation(EXIT_ON_CLOSE); 
      //setBounds(100, 100, 1000, 1000); 
     } 
    } 
} 
+1

感謝您的意見。在你嘗試幫助之後,我真的不想成爲那個人,但請閱讀我的文章中的「不起作用的事情」部分。 這就是爲什麼我的帖子上代碼量最小的版本,所以你可以看到我將對組件進行動態更新,在設置框架可見之前,我無法做到這一點。 它是不是(< - 我不知道這意味着什麼,但它聽起來很酷),主要代碼塊被鏤空。 – Spik330

+0

行..我不好意思閱讀原文更仔細。 *「地圖和瓷磚[]將會經常變化」*如何。究竟?問題是,維護一個遊戲**模型**,更改模型,然後根據更改後的模型更新GUI的外觀或包含GUI的組件,而不是實際更改其他組件的組件。當它實際上需要更換組件時(例如從「菜單面板」翻轉到「遊戲面板」) - 我傾向於使用「CardLayout」(它仍允許在框架設置可見之前添加所有組件)。所以.. –

+0

..你可以詳細瞭解它實際上發生了什麼變化嗎? –