【问题标题】:Repainting a JPanel slightly moves the image on it重新绘制 JPanel 会稍微移动其上的图像
【发布时间】:2014-01-10 13:18:08
【问题描述】:

这是我在这里的第一个问题,如果我做错了什么,请耐心等待。

我正在尝试创建某种地图编辑器。基本上我有一个 2D 瓦片数组,瓦片有地形类型,JPanel 为每个瓦片绘制图像。现在,当我单击一个图块时,地形类型会更改,并且 JPanel 会重新绘制每个已更改的图块。

问题是,当我单击图块时,JPanel 上的图像会以某种方式移动。当我调整窗口大小以便重新绘制每个图块时,一切看起来都正常了。但是当我只更换一个瓷砖时,我无法重新绘制所有内容,这会非常缓慢。

我不知道哪些代码示例与此问题相关,但这是我重写的 paintComponent 方法:

@Override
protected void paintComponent(Graphics g)
{
    super.paintComponents(g);
    Tile[][] tiles = field.getTiles();

    for(int i = 0; i < field.getRows(); i++)
        for(int j = 0; j < field.getColumns(); j++)
        {
            if(field.tileHasChanges(i, j))
            {
                GroundType gt = tiles[i][j].getGround();
                g.drawImage(getGroundImage(gt), j*20, i*20, null);
                field.handledTileChange(i, j);
            }
        }
}

【问题讨论】:

  • 所以你调用的是有参数的repaint()?
  • 您确定这些是正确的:j*20, i*20 在您的 g.drawImage(...) 方法调用中吗?以一种或另一种方式偏离一个像素将产生巨大的影响。另外顺便说一句,getGroundImage(gt) 不会读入文件或资源,对吗?这只会获取您在程序中保存在内存中的图像,对吗?
  • 不,应该吗?我正在使用 drawImage 方法的参数。重绘 JPanel 现在只是 repaint()。
  • 好的,这对你的间距问题没有帮助,但不要从paintComponent方法中读取图像。这种方法将在很大程度上决定您的 GUI 对用户的响应程度,因此它必须精益且快速。相反,将您的图像读入您的班级持有的变量,然后使用这些变量。唯一的例外是当图像非常大时,保存许多图像会使您的内存不足。然后你将不得不缓存到磁盘。关于您的问题,虽然图像是 20 x 20,但它们应该以 20 x 20 显示吗?
  • 考虑创建一个sscce 来重现您的问题。请阅读链接。

标签: java image swing jpanel paintcomponent


【解决方案1】:

与其绘制图像,不如考虑使用 GridLayout 中保存的 JLabels 网格作为地图网格,然后如果要更改网格单元格的图像,只需交换 ImageIcons。

例如,要结合上一个答案 of mine 和 TrashGod's 的代码,请查看此实现:

import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;

@SuppressWarnings("serial")
public class GridExample extends JPanel {
   private Ground[][] groundMap = {
         { Ground.GRASS, Ground.DIRT, Ground.DIRT, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.DIRT, Ground.WATER,
               Ground.WATER, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.WATER,
               Ground.WATER, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.DIRT,
               Ground.WATER, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.DIRT,
               Ground.WATER, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.DIRT,
               Ground.DIRT, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.DIRT, Ground.DIRT,
               Ground.WATER, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.DIRT,
               Ground.DIRT, Ground.WATER, Ground.WATER, Ground.WATER,
               Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.GRASS,
               Ground.GRASS, Ground.DIRT, Ground.DIRT, Ground.DIRT,
               Ground.DIRT, Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.GRASS,
               Ground.GRASS, Ground.DIRT, Ground.DIRT, Ground.DIRT,
               Ground.WATER, Ground.WATER, Ground.WATER },
         { Ground.GRASS, Ground.GRASS, Ground.GRASS, Ground.GRASS,
               Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.DIRT,
               Ground.DIRT, Ground.WATER, Ground.WATER }, };

   private JLabel[][] labelGrid = new JLabel[groundMap.length][groundMap[0].length];

   public GridExample() {
      setLayout(new GridLayout(groundMap.length, groundMap[0].length));
      for (int r = 0; r < labelGrid.length; r++) {
         for (int c = 0; c < labelGrid[r].length; c++) {
            labelGrid[r][c] = new JLabel();
            labelGrid[r][c].setIcon(groundMap[r][c].getIcon());
            add(labelGrid[r][c]);
         }
      }

      addMouseListener(new MyMouseListener());
   }

   private class MyMouseListener extends MouseAdapter {
      @Override
      public void mousePressed(MouseEvent mEvt) {
         Component comp = getComponentAt(mEvt.getPoint());
         for (int row = 0; row < labelGrid.length; row++) {
            for (int col = 0; col < labelGrid[row].length; col++) {
               if (labelGrid[row][col] == comp) {
                  Ground ground = groundMap[row][col];
                  int mapCode = ground.getValue();
                  mapCode++;
                  mapCode %= Ground.values().length;
                  groundMap[row][col] = Ground.values()[mapCode];
                  labelGrid[row][col].setIcon(groundMap[row][col].getIcon());
               }
            }
         }
      }
   }

   private static void createAndShowGui() {
      GridExample mainPanel = new GridExample();

      JFrame frame = new JFrame("GridExample");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

enum Ground {
   DIRT(0, new Color(205, 133, 63)), GRASS(1, new Color(0, 107, 60)), WATER(2,
         new Color(29, 172, 214));
   private int value;
   private Color color;
   private Icon icon;
   private Random random = new Random();

   private Ground(int value, Color color) {
      this.value = value;
      this.color = color;

      icon = createIcon();
   }

   private Icon createIcon() {
      int width = 24;
      BufferedImage img = new BufferedImage(width, width,
            BufferedImage.TYPE_INT_ARGB);
      for (int row = 0; row < width; row++) {
         for (int col = 0; col < width; col++) {
            if (random.nextBoolean()) {
               img.setRGB(col, row, color.getRGB());
            } else {
               if (random.nextBoolean()) {
                  img.setRGB(col, row, color.darker().getRGB());
               } else {
                  img.setRGB(col, row, color.brighter().getRGB());
               }
            }
         }
      }
      return new ImageIcon(img);
   }

   public int getValue() {
      return value;
   }

   public Color getColor() {
      return color;
   }

   public Icon getIcon() {
      return icon;
   }

   public static Ground getGround(int value) {
      for (Ground ground : Ground.values()) {
         if (ground.getValue() == value) {
            return ground;
         }
      }
      return null;
   }

}

【讨论】:

  • 我也想过这个,但是没有找到一个聪明的方法来编写 MouseListener
  • +1 很酷的代码,我喜欢草、泥和水图标的创建方式。
  • @camickr:我不能声称这部分的功劳——那是垃圾神的代码。请点击我回答中的链接并投票赞成他的回答。
【解决方案2】:
 super.paintComponent's'(g);

也许是错字导致了问题。你应该调用super.paintComponent(g),不带“s”。

【讨论】:

  • 我在问之前玩过这个,但两种方法都一样
  • @slowdive,好吧,发布正确的代码,这样你就不会误导别人!
猜你喜欢
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多