Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 正确地画在图像上_Java_Swing_Mouseevent_Bufferedimage_Paintcomponent - Fatal编程技术网

Java 正确地画在图像上

Java 正确地画在图像上,java,swing,mouseevent,bufferedimage,paintcomponent,Java,Swing,Mouseevent,Bufferedimage,Paintcomponent,我正在创建一个小的图像编辑器,现在我正试图让用户通过拖动鼠标(就像MS Paint中的铅笔工具一样)在图像上画图 我遇到了一些困难,因为当我移动光标太快时,应用程序无法绘制所有应该着色的像素,只有一小部分正确着色 我尝试了两种添加彩色像素的解决方案:首先,我创建了一个列表,存储调用mouseDragged时添加的所有点。 之后,我决定在BufferedImage对象上简单地使用setRGB,因为它看起来并不慢 我还做了一个测试,以了解mouseMoved方法是否能够检测到光标悬停的所有点,如果我

我正在创建一个小的图像编辑器,现在我正试图让用户通过拖动鼠标(就像MS Paint中的铅笔工具一样)在图像上画图

我遇到了一些困难,因为当我移动光标太快时,应用程序无法绘制所有应该着色的像素,只有一小部分正确着色

我尝试了两种添加彩色像素的解决方案:首先,我创建了一个列表,存储调用
mouseDragged
时添加的所有点。 之后,我决定在
BufferedImage
对象上简单地使用
setRGB
,因为它看起来并不慢

我还做了一个测试,以了解
mouseMoved
方法是否能够检测到光标悬停的所有点,如果我创建一个列表并将每个点添加到列表中,当我打印列表时,列表中只有一些点,我的结果是否定的

我想我可以再次使用ImagePanel类上的列表,在列表中包含的点之间使用
drawLine
方法,试图填补空白,但我认为这不是一个好的解决方案,因为如果图像被放大,我需要重新发明drawLine方法,并且我还需要找到最佳时机来绘制图像的所有点

有更好的解决办法吗?感谢您的帮助

下面我发布了我的MVCE(我从图像编辑器中删除了所有工具,而且应用程序的设计非常糟糕):

ImagePanel类:

class ImagePanel extends JPanel
{
    private int zoomLevel;
    private BufferedImage image;
    private int rgb = Color.YELLOW.getRGB ();
    private Point lastPoint;

    public ImagePanel () {
        super (new FlowLayout (FlowLayout.LEFT, 0, 0));
        zoomLevel = 1;
    }
    protected void addPoint (int scaledX, int scaledY) {
        int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
        if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
            if (lastPoint == null) image.setRGB (x, y, rgb);
            else {
                Graphics2D g = image.createGraphics ();
                g.setColor (Color.YELLOW);
                g.drawLine (lastPoint.x, lastPoint.y, x, y);
                g.dispose ();
            }
            lastPoint = new Point (x, y);
            refresh ();
        }
    }
    protected int getImageHeight () {
        if (image == null) return 0;
        return image.getHeight ();
    }
    protected int getImageWidth () {
        if (image == null) return 0;
        return image.getWidth ();
    }
    @Override public Dimension getPreferredSize () {
        if (image == null) return new Dimension (0, 0);
        return new Dimension (image.getWidth () * zoomLevel, image.getHeight () * zoomLevel);
    }
    public int getZoomLevel () {
        return zoomLevel;
    }
    @Override protected void paintComponent (Graphics g) {
        super.paintComponent (g);
        g.drawImage (image, 0, 0, image.getWidth () * zoomLevel, image.getHeight () * zoomLevel, this);
    }
    private void refresh () {
        Container parent = getParent ();
        parent.revalidate ();
        parent.repaint ();
    }
    protected void setImage (BufferedImage image) {
        this.image = image;
        refresh ();
    }
    protected void setPixelColor (int scaledX, int scaledY) {
        int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
        if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
            lastPoint = null;
            image.setRGB (x, y, rgb);
            refresh ();
        }
    }
    protected boolean zoom (int zoomLevel) {
        if (image == null || zoomLevel < 1 || zoomLevel > 8) return false;
        this.zoomLevel = zoomLevel;
        refresh ();
        return true;
    }
    protected boolean zoomIn () {
        return image != null && zoom (zoomLevel + 1);
    }
    protected boolean zoomOut () {
        return image != null && zoom (zoomLevel - 1);
    }
}
class ImagePanel扩展了JPanel
{
私人国际zoomLevel;
私有缓冲图像;
private int rgb=Color.YELLOW.getRGB();
私人点;
公共图像面板(){
super(新的FlowLayout(FlowLayout.LEFT,0,0));
zoomLevel=1;
}
受保护的空添加点(int scaledX,int scaledY){
int x=scaledX/zoomLevel,y=scaledY/zoomLevel;
如果(x>=0&&y>=0&&x=0&&y>=0&&x8)返回false;
this.zoomLevel=zoomLevel;
刷新();
返回true;
}
受保护的布尔缩放(){
返回图像!=null&缩放(zoomLevel+1);
}
受保护的布尔zoomOut(){
返回图像!=null&缩放(zoomLevel-1);
}
}

现在它工作得很好

鼠标移动的每一个像素都不会出现鼠标事件,如果移动得非常快,这一点尤其重要。我试图找到一些很好的文档来说明为什么会这样,但无法马上找到。你可能会在那里找到一些东西

要解决这个问题,我要做的是使用
java.awt.Graphics
方法提供的方法,从以前的位置到新的位置画一条线。在你的图像或某个图层上做这个。这里有一些代码可以做到这一点:

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

public class SO46085131 extends JPanel {

    private final Dimension LAYER_SIZE = new Dimension(300, 300);

    private Point prevPoint = null;
    private BufferedImage paintLayer;
    private Graphics paintLayerGraphics;

    public SO46085131(){
        setBackground(Color.black);
        // create our layer that we will paint onto
        paintLayer = new BufferedImage(LAYER_SIZE.width, LAYER_SIZE.height, BufferedImage.TYPE_INT_ARGB);

        // get our graphics for the painting layer and fill in a background cause thats cool
        paintLayerGraphics = paintLayer.getGraphics();
        paintLayerGraphics.setColor(Color.red);
        paintLayerGraphics.fillRect(0, 0, paintLayer.getWidth(), paintLayer.getHeight());

        setBackground(Color.WHITE);
        // listen for drag events, then draw
        // TODO: You should listen for mouse up and down events instead of dragging so you can clear your previous point
        // TODO: Big boy bugs here! for you to fix
        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                // if we moved the mouse previously draw a line from our prev point to our current position
                if(prevPoint != null) {
                    paintLayerGraphics.setColor(Color.black);
                    paintLayerGraphics.drawLine(prevPoint.x, prevPoint.y, e.getX(), e.getY());
                    repaint();
                }
                // store previous point
                prevPoint = e.getPoint();
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // draw our sweet painting layer ontop of our component.
        g.drawImage(paintLayer, 0, 0, this);
    }

    public static void main(String [] args) {
        // just new up a sample jframe to display our stuff on 
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new SO46085131());
        frame.setSize(500, 400);
        frame.setVisible(true);
    }
}

与其尝试单独绘制所有像素,不如在每个像素之间画一条线,这将补偿操作系统不会为“移动的每个像素”生成事件的情况,因为它不会。如果你移动鼠标的速度足够快,操作系统将删除事件,以利于速度和剩余时间responsive@MadProgrammer谢谢你的帮助,我编辑了我的问题,现在效果很好。谢谢你的回答,我使用你的prevPoint方法编辑了我的问题,以避免列出要提取的分数
class ImagePanel extends JPanel
{
    private int zoomLevel;
    private BufferedImage image;
    private int rgb = Color.YELLOW.getRGB ();
    private Point lastPoint;

    public ImagePanel () {
        super (new FlowLayout (FlowLayout.LEFT, 0, 0));
        zoomLevel = 1;
    }
    protected void addPoint (int scaledX, int scaledY) {
        int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
        if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
            if (lastPoint == null) image.setRGB (x, y, rgb);
            else {
                Graphics2D g = image.createGraphics ();
                g.setColor (Color.YELLOW);
                g.drawLine (lastPoint.x, lastPoint.y, x, y);
                g.dispose ();
            }
            lastPoint = new Point (x, y);
            refresh ();
        }
    }
    protected int getImageHeight () {
        if (image == null) return 0;
        return image.getHeight ();
    }
    protected int getImageWidth () {
        if (image == null) return 0;
        return image.getWidth ();
    }
    @Override public Dimension getPreferredSize () {
        if (image == null) return new Dimension (0, 0);
        return new Dimension (image.getWidth () * zoomLevel, image.getHeight () * zoomLevel);
    }
    public int getZoomLevel () {
        return zoomLevel;
    }
    @Override protected void paintComponent (Graphics g) {
        super.paintComponent (g);
        g.drawImage (image, 0, 0, image.getWidth () * zoomLevel, image.getHeight () * zoomLevel, this);
    }
    private void refresh () {
        Container parent = getParent ();
        parent.revalidate ();
        parent.repaint ();
    }
    protected void setImage (BufferedImage image) {
        this.image = image;
        refresh ();
    }
    protected void setPixelColor (int scaledX, int scaledY) {
        int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
        if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
            lastPoint = null;
            image.setRGB (x, y, rgb);
            refresh ();
        }
    }
    protected boolean zoom (int zoomLevel) {
        if (image == null || zoomLevel < 1 || zoomLevel > 8) return false;
        this.zoomLevel = zoomLevel;
        refresh ();
        return true;
    }
    protected boolean zoomIn () {
        return image != null && zoom (zoomLevel + 1);
    }
    protected boolean zoomOut () {
        return image != null && zoom (zoomLevel - 1);
    }
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

public class SO46085131 extends JPanel {

    private final Dimension LAYER_SIZE = new Dimension(300, 300);

    private Point prevPoint = null;
    private BufferedImage paintLayer;
    private Graphics paintLayerGraphics;

    public SO46085131(){
        setBackground(Color.black);
        // create our layer that we will paint onto
        paintLayer = new BufferedImage(LAYER_SIZE.width, LAYER_SIZE.height, BufferedImage.TYPE_INT_ARGB);

        // get our graphics for the painting layer and fill in a background cause thats cool
        paintLayerGraphics = paintLayer.getGraphics();
        paintLayerGraphics.setColor(Color.red);
        paintLayerGraphics.fillRect(0, 0, paintLayer.getWidth(), paintLayer.getHeight());

        setBackground(Color.WHITE);
        // listen for drag events, then draw
        // TODO: You should listen for mouse up and down events instead of dragging so you can clear your previous point
        // TODO: Big boy bugs here! for you to fix
        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                // if we moved the mouse previously draw a line from our prev point to our current position
                if(prevPoint != null) {
                    paintLayerGraphics.setColor(Color.black);
                    paintLayerGraphics.drawLine(prevPoint.x, prevPoint.y, e.getX(), e.getY());
                    repaint();
                }
                // store previous point
                prevPoint = e.getPoint();
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // draw our sweet painting layer ontop of our component.
        g.drawImage(paintLayer, 0, 0, this);
    }

    public static void main(String [] args) {
        // just new up a sample jframe to display our stuff on 
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new SO46085131());
        frame.setSize(500, 400);
        frame.setVisible(true);
    }
}