Java рисовать не рисовать в Swing

1

Я пытаюсь сделать программу рисования, но у меня возникают проблемы с рисованием линий при перетаскивании мыши. Похоже, что краска продолжает освежать, и поэтому она только рисует текущее положение мыши. Я немного новичок в этом, так как я смогу получить все строки, чтобы показать на 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);


        }

    }
}
Теги:
swing

3 ответа

2
Лучший ответ

Существует несколько способов решения вашей проблемы. @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: вам нужно знать размер холста, прежде чем начинать рисовать.

  • 0
    Так что, если я добавлю больше функций в мою программу (например, рисование прямоугольника, овала и т. Д.), Будет ли подход к изображению более подходящим, чем перерисовывание прошлых картин?
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();
}

с:

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

Теперь мы сохраняем каждую законченную строку в списке, каждый четный индекс - это начало строки, а каждый нечетный - конец строки. Если вы хотите рисовать "кривые", которые выглядят точно так же, как вы перемещали мышь, вам нужно немного изменить этот код, но по крайней мере это должно дать вам кое-что, с чем можно работать. Просто отправьте дополнительный вопрос, если вам нужна дополнительная помощь.

  • 0
    Это имеет больше смысла сейчас. Что если я хочу нарисовать разные цветные линии? Составить ли список цветов?
  • 0
    Да, у меня просто есть отдельный список цветов, где цвет в списке цветов по индексу i соответствует линии с начальной точкой в points.get (i * 2)
2

Кажется, что краска продолжает освежающе

Да, это то, как работает живопись, посмотрите на картину в AWT и Swing для получения более подробной информации

В качестве возможного решения вы можете добавить каждый новый Point a List и просто нарисовать линию между каждой точкой в методе paintComponent, выполнив итерацию над List.

Вы также можете создать Shape и нарисовать линии внутри и нарисовать эту фигуру в методе paintComponent.

Взгляните на 2D-графику для более подробной информации.

Пример рисования отдельных строк

Изображение 174551

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

    }

}

Пример рисования нескольких связанных строк

Изображение 174551

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

    }

}
  • 0
    Хорошо, я посмотрю на это. Я все еще немного неуверен в том, как подойти к решению (извините за отсутствие знаний).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню