【问题标题】:Draw accurately on an image in Java在 Java 中准确地绘制图像
【发布时间】:2012-10-16 15:58:49
【问题描述】:

在下面的代码中,我将 2dim 数组转换为缓冲图像(有效,图像是二进制的(背面和白色))。然后我显示这个图像。

我现在的问题是如何更新此图像(因为我想在每次循环运行时绘制一些未在此处显示的内容)。

这也引出了我的第二个问题:如何在这张图片上画一个点。 (这也意味着如果我想在 150,100 上画一个点;它应该在图像的 150,100 像素上)。

public void showImage(int xPoint, int yPoint) throws IOException {

    // Two dim array conversion to a bufferedImage
    BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int y = 0; y < width; y++) {
        for (int x = 0; x < height; x++) {

            tempValue = (pixelArray[y][x]==1) ? 255 : 0;
            int value = tempValue << 16 | tempValue << 8 | tempValue;
            bimg.setRGB(x, y, value);

        }
    }

    JFrame canvas = new JFrame();
    canvas.setSize(bimg.getWidth(), bimg.getHeight());
    canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    canvas.setTitle("Contour");
    Container pane = canvas.getContentPane();
    ColorPanel panel = new ColorPanel(bimg,xPoint,yPoint);
    pane.add(panel);
    canvas.setVisible(true);
}

    class ColorPanel extends JPanel {
    BufferedImage bimg;
    int x;
    int y;

    public ColorPanel(BufferedImage image,int _x, int _y) {
        bimg = image;
        x = _x;
        y = _y;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(bimg, null, 0, 0);
    }
}

我尝试的是:

  g2d.setColor(Color.RED);
  g2d.drawLine(x, y, x, y);

虽然每次运行都会打开一个新窗口,但我不认为重点是正确的

【问题讨论】:

  • 我认为必须为 JPanel 覆盖 PreferredSize
  • “虽然每次运行都会打开一个新窗口”。因为您在每次调用 showImage() 时都会创建一个新的 JFrame。如需更多帮助,请发布 SSCCE
  • @David Huh.. 好点。我的立场是正确的。

标签: java swing jpanel bufferedimage paintcomponent


【解决方案1】:

我为你做了一个小例子。

基本上它是一个带有 custom JPanelJFrame,称为 ColorPanel(这很像你的,有一些额外的方法,即 drawDot(..)setBufferedImage(..)

JFrame 将初始化并添加JPanelBufferedImage(在这种情况下完全黑色)。此后 白色 点/像素将使用 BufferedImage#setRGB(...) 每 2 秒以随机坐标(在图像边界内)在 Image 上绘制。

我将计时器设置为更快(200milis),这就是图片开始的样子:

注意它是准确的,让它像drawPoint(0,0) 一样为一个明显的坐标着色,你会看到(我没有证明这一点,因为截图是不可能的或没有任何用处)

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class PixelDotOnImage {

    public PixelDotOnImage() throws Exception {
        JFrame frame = new JFrame();
        frame.setTitle("Random Pixel Dots On Image with Timer");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        initComponents(frame);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        //create frame and components on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new PixelDotOnImage();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    private void initComponents(JFrame frame) throws Exception {

        final BufferedImage bi = ImageIO.read(new URL("http://2.bp.blogspot.com/_KI3IRH6RxSs/S-uuLsgGJ3I/AAAAAAAAA5E/AA5mWBMLIvo/s1600/mat-black-lg.jpg"));
        final ColorPanel cPanel = new ColorPanel(bi);
        frame.add(cPanel);

        //create timer to color random pixels
        Timer timer = new Timer(2000, new AbstractAction() {
            int xMax = bi.getWidth(), yMax = bi.getHeight();
            Random rand = new Random();

            @Override
            public void actionPerformed(ActionEvent ae) {

                int x = rand.nextInt(xMax);
                int y = rand.nextInt(yMax);

                if (cPanel.drawDot(x, y)) {
                    System.out.println("Drew white dot at: (" + x + "," + y + ")");
                } else {
                    System.out.println("Cant draw white dot at: (" + x + "," + y + ")");
                }

            }
        });

        timer.start();
    }
}

class ColorPanel extends JPanel {

    private BufferedImage bimg;
    private Dimension dims;

    public ColorPanel(BufferedImage image) {
        bimg = image;
        dims = new Dimension(bimg.getWidth(), bimg.getHeight());
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(bimg, 0, 0, null);
    }

    //this method will allow the changing of image
    public void setBufferedImage(BufferedImage newImg) {
        bimg = newImg;
    }

    //ths method will colour a pixel white
    public boolean drawDot(int x, int y) {

        if (x > dims.getWidth() || y > dims.getHeight()) {
            return false;
        }

        bimg.setRGB(x, y,  0xFFFFFFFF);//white

        repaint();
        return true;
    }

    @Override
    public Dimension getPreferredSize() {
        return dims;
    }
}

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    与其构建图像然后将其添加到 JPanel,不如考虑通过覆盖它的paintComponent 方法来直接在面板上进行绘图,如下所示:

    public class PainterPanel extends JPanel {
        public void paintComponent(Graphics g){     
            super.paintComponent(g);
    
            // draw a diagonal line from top left to bottom right
            Dimension d = getSize();
            g2.draw(new Line2D.Double(0,0,d.width,d.height));
        }
    }
    

    每次调用repaint() 方法时都会调用此方法(例如,通过调整框架大小,或通过自己手动调用)。您可以进行任何所需的复杂处理,包括绘制点矩阵。

    唯一的问题(如果您也坚持原来的行为,这将是真的)是重新绘制发生在一个单独的线程中,因此您需要注意何时以及如何更新数据,以便在一种线程安全的方式。

    【讨论】:

      【解决方案3】:

      如何更新这张图片

      • 要在图像上绘图,请使用通过 bimg.getGraphics() 获得的图形(然后像在 paintComponent 中一样使用它)。 See Javadocs

      如何在这张图片上画一个点

      • 要在缓冲图像的特定点上绘画,请使用从上述答案中检索到的图形对象的任何方法。示例g.drawLine(150,100,150,100)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多