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

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

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

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

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

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

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

 private BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB); private Graphics2D imageGraphics = image.createGraphics(); public class ml extends MouseAdapter implements MouseMotionListener, MouseListener { public void mousePressed(MouseEvent e) { end = e.getPoint(); } public void mouseDragged(MouseEvent e) { start = end; end = e.getPoint(); imageGraphics.setColor(c); imageGraphics.setStroke(new BasicStroke(5)); imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); imageGraphics.drawLine(start.x, start.y, end.x, end.y); repaint(); } public void mouseReleased(MouseEvent e) { start = null; end = null; } } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.drawImage(image, null, 0, 0); } 

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

你做的几乎一切都是正确的。 程序仅显示当前鼠标位置的原因是因为您没有在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(); } 

有:

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

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

 private ArrayList points = new ArrayList(); 

也取代这个:

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

有:

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

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

看来油漆一直在刷新

是的,这就是绘画的作用,看看AWT和Swing中的绘画了解更多细节

作为一种可能的解决方案,您可以添加每个新的Point一个List并通过遍历List简单地在paintComponent方法中的每个点之间绘制一条线。

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

有关详细信息,请查看2D图形

绘制单行的示例

画线

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

绘制多条连接线的示例

连接线

 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 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, px, py); startPoint = p; } } if (startPoint != null) { g2d.setColor(Color.RED); g2d.drawLine(startPoint.x, startPoint.y, mousePoint.x, mousePoint.y); } g2d.dispose(); } } }