我正在尝试制作一个绘画程序,但是在拖动鼠标时我遇到绘制线条的麻烦。看起来油漆不断刷新,因此它只绘制鼠标的当前位置。 我对此有点新鲜,那么在拖动鼠标时如何才能获得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);
}
}
}
答案 0 :(得分:2)
看来油漆一直在刷新
是的,这就是绘画的工作方式,请查看Painting in AWT and Swing了解更多详情
作为一种可能的解决方案,您可以添加每个新的Point
一个List
,并通过迭代paintComponent
在List
方法中的每个点之间绘制一条线。
您还可以创建Shape
并在其中绘制线条并在paintComponent
方法中绘制此形状。
请查看2D Graphics了解详情
绘制单行的示例
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();
}
}
}
绘制多条连线的示例
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绘图操作列表。缺点是它使用了更多的内存(直到你有很多绘图操作)并且你不能完全上下缩放你的图像。
要让您的示例使用保留在内存中的位图,请将字段image
和imageGraphics
添加到您的类中,并替换您的鼠标侦听器ml
以及{{1使用以下代码的方法:
paintComponent
您将立即看到缩放问题。位图缓冲区为500x500像素,其外部的任何内容都不会被绘制。这与Microsoft绘制的工作方式基本相同:在开始绘制之前,您需要知道画布大小。