Java绘画没有在Swing中绘制

时间:2014-05-31 04:09:25

标签: java swing

我正在尝试制作一个绘画程序,但是在拖动鼠标时我遇到绘制线条的麻烦。看起来油漆不断刷新,因此它只绘制鼠标的当前位置。 我对此有点新鲜,那么在拖动鼠标时如何才能获得JPanel上显示的所有行?谢谢,这就是我所拥有的:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JPanel;

public class DrawingPanel extends JPanel{

    Point start;
    Point end;
    static Color c = Color.black;
    DrawingPanel(){
        addMouseMotionListener(new ml());
        addMouseListener(new ml());
    }
    public class ml implements MouseMotionListener, MouseListener{
        public void mouseMoved(MouseEvent ev){}
        public void mousePressed(MouseEvent e){
            end = e.getPoint();
        }
        public void mouseDragged(MouseEvent e){
            start = end;
            end=e.getPoint();
            repaint();
        }
        public void mouseReleased(MouseEvent e){
            start=null;
            end=null;
        }
        public void mouseClicked(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e){}
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(c);
        if(start!=null){
            Graphics2D g2 = (Graphics2D) g;
            g2.setStroke(new BasicStroke(5));
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.drawLine(start.x, start.y, end.x, end.y);


        }

    }
}

3 个答案:

答案 0 :(得分:2)

  

看来油漆一直在刷新

是的,这就是绘画的工作方式,请查看Painting in AWT and Swing了解更多详情

作为一种可能的解决方案,您可以添加每个新的Point一个List,并通过迭代paintComponentList方法中的每个点之间绘制一条线。

您还可以创建Shape并在其中绘制线条并在paintComponent方法中绘制此形状。

请查看2D Graphics了解详情

绘制单行的示例

DrawLines

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DrawLine {

    public static void main(String[] args) {
        new DrawLine();
    }

    public DrawLine() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Point startPoint, endPoint;

        private List<Point[]> lines;

        public TestPane() {

            lines = new ArrayList<>(25);

            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent e) {
                    startPoint = e.getPoint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    endPoint = e.getPoint();
                    Point[] points = new Point[]{startPoint, endPoint};
                    lines.add(points);
                    startPoint = null;
                    endPoint = null;
                    repaint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    endPoint = e.getPoint();
                    repaint();
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLACK);
            for (Point[] p : lines) {
                g2d.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
            }
            if (startPoint != null && endPoint != null) {
                g2d.setColor(Color.RED);
                g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
            }
            g2d.dispose();
        }

    }

}

绘制多条连线的示例

Connected lines

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DrawLine {

    public static void main(String[] args) {
        new DrawLine();
    }

    public DrawLine() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private List<Point> points;
        private Point mousePoint;

        public TestPane() {

            points = new ArrayList<>(25);

            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    points.add(e.getPoint());
                    repaint();
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                    mousePoint = e.getPoint();
                    repaint();
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLACK);
            Point startPoint = null;
            for (Point p : points) {
                if (startPoint == null) {
                    startPoint = p;
                } else {
                    g2d.drawLine(startPoint.x, startPoint.y, p.x, p.y);
                    startPoint = p;
                }
            }
            if (startPoint != null) {
                g2d.setColor(Color.RED);
                g2d.drawLine(startPoint.x, startPoint.y, mousePoint.x, mousePoint.y);
            }
            g2d.dispose();
        }

    }

}

答案 1 :(得分:2)

你做的几乎一切都是正确的。程序仅显示当前鼠标位置的原因是因为您没有在mousePressed上保存起始位置。尝试更换:

public void mousePressed(MouseEvent e){
    end = e.getPoint();
}

使用:

public void mousePressed(MouseEvent e){
    start = e.getPoint();
}

还有:

public void mouseDragged(MouseEvent e){
    start = end;
    end=e.getPoint();
    repaint();
}

with:

public void mouseDragged(MouseEvent e){
    end = e.getPoint();
    repaint();
}

这将使它能够绘制一条线。如果您想要更多行,您可以将每个完成的行添加到mouseReleased中的列表中。尝试将其添加到DrawingPanel类:

private ArrayList<Point> points = new ArrayList<Point>();

也取代了这个:

public void mouseReleased(MouseEvent e){
    start = null;
    end   = null;
}

使用:

public void mouseReleased(MouseEvent e){
    points.add(start);
    points.add(end);
    start = null;
    end   = null;
}

并取代:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    g.setColor(c);
    if(start!=null){
        Graphics2D g2 = (Graphics2D) g;
        g2.setStroke(new BasicStroke(5));
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.drawLine(start.x, start.y, end.x, end.y);
    }
}

with:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(c);
    g2.setStroke(new BasicStroke(5));
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    //Draw all previous lines
    for (int i = 0; i < points.size(); i+=2) {
        g2.drawLine(points.get(i).x, points.get(i).y, points.get(i+1).x, points.get(i+1).y);
    }

    //Draw the current line if there is one
    if(start != null && end != null){
        g2.drawLine(start.x, start.y, end.x, end.y);
    }
}

现在我们将每个完成的行保存在列表中,每个偶数索引是一行的开头,每个奇数是一行的结尾。如果你想能够绘制看起来与你移动鼠标完全相同的“曲线”,你必须稍微改变一下这个代码,但至少这应该给你一些工作。如果您需要进一步的帮助,只需提交一个额外的问题。

答案 2 :(得分:2)

有多种方法可以解决您的问题。 @MattiasF和@MadProgrammer是正确的:Swing正在做它应该做的事情。您的paintComponent方法应该重新绘制整个场景,而不是添加到前一个场景。

到目前为止建议的解决方案导致应用程序正在执行矢量图形:您正在记住原始绘图操作,并且在每个绘图上,您正在执行它们中的每一个(Java2D优化其中的一些,因为它不会真正重新绘制屏幕上当前不可见的区域,但是还需要时间来确定哪些区域可见,哪些区域不可见

优点是,如果您需要更大或更小的图像,您可以完美地缩放绘图操作。缺点是,一旦存储了许多绘图操作,它可能会变慢,并且您不能(轻松地)进行位图操作。

另一种方法是位图方法。到目前为止,您在内存中构建了一个绘图位图,并在paintComponent方法中将位图绘制到屏幕上。

优势在于它通常更快。它还允许位图操作,并且通常更容易针对此模型进行编程,因为您可以在需要时绘制,而不是在内存中构建op绘图操作列表。缺点是它使用了更多的内存(直到你有很多绘图操作)并且你不能完全上下缩放你的图像。

要让您的示例使用保留在内存中的位图,请将字段imageimageGraphics添加到您的类中,并替换您的鼠标侦听器ml以及{{1使用以下代码的方法:

paintComponent

您将立即看到缩放问题。位图缓冲区为500x500像素,其外部的任何内容都不会被绘制。这与Microsoft绘制的工作方式基本相同:在开始绘制之前,您需要知道画布大小。