Я пытаюсь сделать программу рисования, но у меня возникают проблемы с рисованием линий при перетаскивании мыши. Похоже, что краска продолжает освежать, и поэтому она только рисует текущее положение мыши. Я немного новичок в этом, так как я смогу получить все строки, чтобы показать на 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
вы рисуете растровое изображение на экране.
Преимущество состоит в том, что он обычно быстрее. Он также позволяет работать с растровыми изображениями, а также часто проще программировать против этой модели, поскольку вы можете просто рисовать, когда вам это нужно, вместо того, чтобы создавать список операций рисования в памяти. Недостатком является то, что он использует больше памяти (до тех пор, пока у вас не будет много операций рисования), и что вы не сможете полностью масштабировать изображение вверх и вниз.
Для того, чтобы ваш пример работа с растровым изображением сохраняется в памяти, добавьте поля image
и imageGraphics
в свой класс, и заменить слушатель мыши 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);
}
Вы сразу увидите проблему с масштабированием. Буфер растрового изображения 500x500 пикселей, и ничего вне его не будет рисоваться. Это в основном так же, как работает краска Microsoft: вам нужно знать размер холста, прежде чем начинать рисовать.
Вы сделали почти все правильно. Причина, по которой ваша программа показывает текущую позицию мыши, заключается в том, что вы не сохраняете начальную позицию на 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<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);
}
}
с:
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
a List
и просто нарисовать линию между каждой точкой в методе paintComponent
, выполнив итерацию над List
.
Вы также можете создать 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<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();
}
}
}