java - 除非 JFrame.validate(),否则 JPanel JComponent 不会重新绘制;将组件添加到可见框架后调用

标签 java image swing jframe

Frame -> MainContentPane -> MapPanel -> map -> Tile[]

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

我正在尝试在 JPanel 上绘制 32x32 像素图 block ,但无论我在哪里调用 repaint();如果我调用 validate(),它只会绘制瓷砖;在 JFrame 上。 如果我绕过面板并直接在 MapPanel 上绘制(使用 draw() 方法),则仅当我调整大小或移动 JFrame 以使框架具有由repaintmanager重新绘制。但是,在我的 ContentPanel 上调用 repaint()validate() 或两者都不会绘制图像。

如果我理解 Java.swing 如何正确绘制事物,如果我在最高级别的组件上调用重绘,它应该重新绘制 repaintmanager 认为应该重新绘制的所有子组件。由于我在框架设置为可见后添加组件,因此我需要在最高级别组件上调用 validate() 来告诉 repaintmanager 有新的东西。我的这种理解正确吗?

不起作用的事情:

告诉我在将框架设置为可见之前添加所有组件。 MapTile[] 会定期更改,每次添加/删除某些内容时都重置 Frame 是非常不切实际的。

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();如果面板上没有任何内容需要无效。我的想法正确吗?

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);
    }
}
}

最佳答案

发布的代码的基本问题是在添加组件之前将 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);
        }
    }
}

关于java - 除非 JFrame.validate(),否则 JPanel JComponent 不会重新绘制;将组件添加到可见框架后调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43175571/

相关文章:

java - 是否可以使用 "$1"作为另一个方法的参数并将返回的字符串放在 .replaceAll 中的位置?

Java:jsp+hibernate 与 eclipse。示例应用程序?

Python平滑曲线

image - 从像素缓冲区 blitting 到设备上下文的最快方法

javascript - dojo/使用NodeJS请求一个png图像数组缓冲区,并将图像返回给客户端

java - 在文本区域附加中格式化。 java

java - 如何摆脱 Hibernate/JPA 上的 N+1 查询,使用其父 ID 更新子行

java - 策略设计模式中获取对象的类名

java - 更改 swing 应用程序的外观和感觉 (UIManager) 时出错

java - 在单击事件上更改 JButton