Как нарисовать изогнутые линии на экране с помощью LinkedList и MouseListeners? - PullRequest
0 голосов
/ 13 июня 2018

Я новичок в Java. Что касается окончательного проекта моего класса, я занимаюсь разработкой приложения для рисования, которое позволяет пользователям рисовать богатые изогнутые линии и обычные геометрические фигуры, такие как прямоугольник и овал, а также пользователи могут отменить рисунок формы.

Мое приложение хорошо работало на рисовании фигур.Когда я хочу рисовать фигуры, фигуры, которые я хочу рисовать, сохраняются в LinkedList, который будет вызываться для рисования фигур на экране. Когда я применил эту концепцию LinkedList для рисования кривых линий на экране.Я изменил код рисования формы, чтобы нарисовать изогнутые линии.Я столкнулся с проблемой;В результате я получил маленькие точки на экране. Если бы я попытался скопировать подобный код, который рисует фигуры для рисования изогнутых линий, я бы получил прямые линии вместо изогнутых линий.

Iдумаю, что эта проблема связана с интерфейсами MouseListener.Мне нужны некоторые предложения о том, как я могу изменить методы MouseListener, чтобы я мог правильно рисовать кривые линии на экране.

Изменения в моем исходном коде приветствуются:

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PaintAppPlusSecondDraft extends JApplet implements ActionListener {
private static final long serialVersionUID = 1L;

private JMenuBar menuBar = new JMenuBar();

private JMenu mainMenu = new JMenu("Main menu");
private JMenuItem howToUse = new JMenuItem("How to use?");
private JMenuItem toDefaultMode = new JMenuItem("Return to default mode");

private JMenu boardSettings = new JMenu("Paint board settings");
private JMenuItem clearBoard = new JMenuItem("Clear screen");
private JMenuItem toDefaultBoard = new JMenuItem("Set to default paint board");
private JMenuItem bCustom = new JMenuItem("Set background colour");

private JMenu brushSettings = new JMenu("Paintbrush settings");
private JMenuItem eraser = new JMenuItem("Eraser");
private JMenuItem toDefaultBrush = new JMenuItem("Set to default paintbrush");
private JMenu setBrushSize = new JMenu("Set paintbrush size");
private JMenuItem Two = new JMenuItem("2 pixels");
private JMenuItem Four = new JMenuItem("4 pixels");
private JMenuItem Six = new JMenuItem("6 pixels");
private JMenuItem Eight = new JMenuItem("8 pixels");
private JMenuItem Ten = new JMenuItem("10 pixels");
private JMenu setBrushType = new JMenu("Set paintbrush type");
private JMenuItem defaultType1 = new JMenuItem("Default");
private JMenuItem defaultType2 = new JMenuItem("Default (light stroke)");
private JMenuItem Custom = new JMenuItem("Set paintbrush colour");

private JMenu drawShapes = new JMenu("Draw shapes");
private JMenuItem undoShape = new JMenuItem("Undo shape drawing");
private JMenuItem StraightLine = new JMenuItem("Straight line");
private JMenuItem Rectangle = new JMenuItem("Rectangle");
private JMenuItem Oval = new JMenuItem("Oval");
private JMenuItem filledRectangle = new JMenuItem("Filled rectangle");
private JMenuItem filledOval = new JMenuItem("Filled oval");

private int prevBrushSize = PaintBoard.brushSize;
private int prevBrushType = PaintBoard.brushType;
private Color prevBrushColour = PaintBoard.currentColour; /* For better user experience */

public void init() {
    Frame frame = (Frame) getParent().getParent();
    frame.setTitle("JAVA Paint plus");
    frame.setResizable(false);

    this.setSize(600, 400);
    this.setContentPane(new PaintBoard());

    mainMenu.add(howToUse);
    mainMenu.add(toDefaultMode);
    mainMenu.add(about);

    boardSettings.add(clearBoard);
    boardSettings.add(toDefaultBoard);
    boardSettings.add(bCustom);

    brushSettings.add(eraser);
    brushSettings.add(toDefaultBrush);
    setBrushSize.add(Two);
    setBrushSize.add(Four);
    setBrushSize.add(Six);
    setBrushSize.add(Eight);
    setBrushSize.add(Ten);
    brushSettings.add(setBrushSize);
    setBrushType.add(defaultType1);
    setBrushType.add(defaultType2);
    setBrushType.add(waterColourBrush);
    setBrushType.add(triangleType);
    setBrushType.add(squareType);
    setBrushType.add(hexagonType);
    setBrushType.add(starType);
    setBrushType.add(heartType);
    brushSettings.add(setBrushType);
    brushSettings.add(Custom);

    drawShapes.add(undoShape);
    drawShapes.add(StraightLine);
    drawShapes.add(Rectangle);
    drawShapes.add(Oval);
    drawShapes.add(filledRectangle);
    drawShapes.add(filledOval);

    menuBar.add(mainMenu);
    menuBar.add(boardSettings);
    menuBar.add(brushSettings);
    menuBar.add(drawShapes);

    howToUse.addActionListener(this);
    toDefaultMode.addActionListener(this);

    clearBoard.addActionListener(this);
    toDefaultBoard.addActionListener(this);
    bCustom.addActionListener(this);

    eraser.addActionListener(this);
    toDefaultBrush.addActionListener(this);
    Two.addActionListener(this);
    Four.addActionListener(this);
    Six.addActionListener(this);
    Eight.addActionListener(this);
    Ten.addActionListener(this);
    defaultType1.addActionListener(this);
    defaultType2.addActionListener(this);
    Custom.addActionListener(this);

    undoShape.addActionListener(this);
    StraightLine.addActionListener(this);
    Rectangle.addActionListener(this);
    Oval.addActionListener(this);
    filledRectangle.addActionListener(this);
    filledOval.addActionListener(this);

    this.setJMenuBar(menuBar);
    this.setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == howToUse) {
        JOptionPane.showMessageDialog(null, "Press your mouse on the board and drag to draw!", "How to use?", JOptionPane.INFORMATION_MESSAGE);
    }

    if (e.getSource() == toDefaultMode) {
        PaintBoard.canvasColour = Color.WHITE;
        PaintBoard.brushSize = prevBrushSize = 6;
        PaintBoard.brushType = prevBrushType = 1;
        PaintBoard.currentColour = prevBrushColour = Color.BLACK;
        PaintBoard.shapes.makeEmpty();
        repaint();
    }

    if (e.getSource() == clearBoard) {
        PaintBoard.shapes.makeEmpty();
        repaint();
    }

    if (e.getSource() == toDefaultBoard) {
        PaintBoard.canvasColour = Color.WHITE;
        repaint();
    }

    if (e.getSource() == bCustom) {
        try {
            Color customColour = JColorChooser.showDialog(null, "Select colour:", PaintBoard.canvasColour);

            PaintBoard.canvasColour = customColour;
            PaintBoard.shapes.makeEmpty();
            repaint();
        } catch (NullPointerException ex) {

        }
    }

    if (e.getSource() == eraser) {
        prevBrushSize = PaintBoard.brushSize;
        prevBrushType = PaintBoard.brushType;
        prevBrushColour = PaintBoard.currentColour;
        PaintBoard.brushSize = 44;
        PaintBoard.brushType = 1;
        PaintBoard.currentColour = PaintBoard.canvasColour;
    }

    if (e.getSource() == toDefaultBrush) {
        PaintBoard.brushSize = prevBrushSize = 6;
        PaintBoard.brushType = prevBrushType = 1;
        PaintBoard.currentColour = prevBrushColour = Color.BLACK;
    }

    if (e.getSource() == Two) {
        PaintBoard.brushSize = prevBrushSize = 2;
        PaintBoard.brushType = prevBrushType;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == Four) {
        PaintBoard.brushSize = prevBrushSize = 4;
        PaintBoard.brushType = prevBrushType;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == Six) {
        PaintBoard.brushSize = prevBrushSize = 6;
        PaintBoard.brushType = prevBrushType;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == Eight) {
        PaintBoard.brushSize = prevBrushSize = 8;
        PaintBoard.brushType = prevBrushType;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == Ten) {
        PaintBoard.brushSize = prevBrushSize = 10;
        PaintBoard.brushType = prevBrushType;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == defaultType1) {
        PaintBoard.brushSize = prevBrushSize;
        PaintBoard.brushType = prevBrushType = 1;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == defaultType2) {
        PaintBoard.brushSize = prevBrushSize;
        PaintBoard.brushType = prevBrushType = 2;
        PaintBoard.currentColour = prevBrushColour;
    }

    if (e.getSource() == Custom) {
        try {
            Color customColour = JColorChooser.showDialog(null, "Select colour:", PaintBoard.currentColour);

            PaintBoard.brushSize = prevBrushSize;
            PaintBoard.brushType = prevBrushType;
            PaintBoard.currentColour = prevBrushColour = customColour;
        } catch (NullPointerException ex) {

        }
    }

    if (e.getSource() == undoShape) {
        try {
            PaintBoard.shapes.removeFront();
            repaint();
        } catch (NullPointerException ex) {

        }
    }

    if (e.getSource() == StraightLine) {
        PaintBoard.brushSize = prevBrushSize;
        PaintBoard.currentColour = prevBrushColour;
        PaintBoard.shapeType = 1;
    }

    if (e.getSource() == Rectangle) {
        PaintBoard.currentColour = prevBrushColour;
        PaintBoard.shapeType = 2;
        PaintBoard.filled = false;
    }

    if (e.getSource() == Oval) {
        PaintBoard.currentColour = prevBrushColour;
        PaintBoard.shapeType = 3;
        PaintBoard.filled = false;
    }

    if (e.getSource() == filledRectangle) {
        PaintBoard.currentColour = prevBrushColour;
        PaintBoard.shapeType = 2;
        PaintBoard.filled = true;
    }

    if (e.getSource() == filledOval) {
        PaintBoard.currentColour = prevBrushColour;
        PaintBoard.shapeType = 3;
        PaintBoard.filled = true;
    }
}

abstract static class brushLine {
    private int brushSize;
    private int brushType;
    private Color brushColour;

    public brushLine() {
        brushSize = 6;
        brushType = 1;
        brushColour = Color.BLACK;
    }

    public brushLine(int brushSize, int brushType, Color brushColour) {
        this.brushSize = brushSize;
        this.brushType = brushType;
        this.brushColour = brushColour;
    }

    public void setBrushSize(int brushSize) {
        this.brushSize = brushSize;
    }

    public void setBrushType(int brushType) {
        this.brushType = brushType;
    }

    public void setBrushColour(Color brushColour) {
        this.brushColour = brushColour;
    }

    public int getBrushSize() {
        return brushSize;
    }

    public int getBrushType() {
        return brushType;
    }

    public Color getBrushColour() {
        return brushColour;
    }

    abstract void show(Graphics window);
}

static class paintBrushLine extends brushLine {
    private int x1, y1, x2, y2;

    public paintBrushLine() {
        super();
        x1 = 0;
        y1 = 0;
        x2 = 0;
        y2 = 0;
    }

    public paintBrushLine(int brushSize, int brushType, Color brushColour, int x1, int y1, int x2, int y2) {
        super(brushSize, brushType, brushColour);
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    public void setX1(int x1) {
        this.x1 = x1;
    }

    public void setY1(int y1) {
        this.y1 = y1;
    }

    public void setX2(int x2) {
        this.x2 = x2;
    }

    public void setY2(int y2) {
        this.y2 = y2;
    }

    public int getX1() {
        return x1;
    }

    public int getY1() {
        return y1;
    }

    public int getX2() {
        return x2;
    }

    public int getY2() {
        return y2;
    }

    public void show(Graphics window) {
        window.setColor(getBrushColour());

        switch (getBrushType()) {

        case 1://Default brush
            ((Graphics2D) window).setStroke(new BasicStroke(getBrushSize(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            window.drawLine(getX1(), getY1(), getX2(), getY2());
            break;
        case 2://Default brush (light stroke) --> Makes empty squares with few randomly positioned pixels
            int[] pixelPos = new int[2];

            for (int i = 0; i < ((getBrushSize()*getBrushSize()) / 10); i++) {
                pixelPos[0] = new Random().nextInt(getBrushSize());
                pixelPos[1] = new Random().nextInt(getBrushSize());

                window.drawRect(getX1() + pixelPos[0], getY1() + pixelPos[1], 1, 1);
            }

            break;
        }
    }
}

abstract static class Shape {
    private int x1, y1, x2, y2;
    private int thickness;
    private Color shapeColour;

    public Shape() {
        x1 = 0;
        y1 = 0;
        x2 = 0;
        y2 = 0;
        shapeColour = Color.BLACK;
    }

    public Shape(int x1, int y1, int x2, int y2, int thickness, Color shapeColour)
    {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.thickness = thickness;
        this.shapeColour = shapeColour;
    }

    public void setX1(int x1) {
        this.x1 = x1;
    }

    public void setY1(int y1) {
        this.y1 = y1;
    }

    public void setX2(int x2) {
        this.x2 = x2;
    }

    public void setY2(int y2) {
        this.y2 = y2;
    }

    public void setThickness(int thickness) {
        this.thickness = thickness;
    }

    public void setShapeColour(Color shapeColour) {
        this.shapeColour = shapeColour;
    }

    public int getX1() {
        return x1;
    }

    public int getY1() {
        return y1;
    }

    public int getX2() {
        return x2;
    }

    public int getY2() {
        return y2;
    }

    public int getThickness() {
        return thickness;
    }

    public Color getShapeColour() {
        return shapeColour;
    }

    abstract void sketch(Graphics window);
}

abstract static class boundedShape extends Shape {
    private int shapeType;
    private boolean filled;

    public boundedShape() {
        super();
        filled = false;
    }

    public boundedShape(int x1, int y1, int x2, int y2, int thickness, Color shapeColour, int shapeType, boolean filled) {
        super(x1, y1, x2, y2, thickness, shapeColour);
        this.shapeType = shapeType;
        this.filled = filled;
    }

    public void setShapeType(int shapeType) {
        this.shapeType = shapeType;
    }

    public void setFilled(boolean filled) {
        this.filled = filled;
    }

    public int getUpperLeftX() {
        return Math.min(getX1(), getX2());
    }

    public int getUpperLeftY() {
        return Math.min(getY1(), getY2());
    }

    public int getWidth() {
        return Math.abs(getX1() - getX2());
    }


    public int getHeight() {
        return Math.abs(getY1() - getY2());
    }

    public int getShapeType() {
        return shapeType;
    }

    public boolean getFilled() {
        return filled;
    }

    abstract public void sketch(Graphics window);
}

static class geometricShape extends boundedShape {
    public geometricShape() {
        super();
    }

    public geometricShape(int x1, int y1, int x2, int y2, int thickness, Color shapeColour, int shapeType, boolean filled) {
        super(x1, y1, x2, y2, thickness, shapeColour, shapeType, filled);
    }

    public void sketch(Graphics window) {
        window.setColor(getShapeColour());

        switch(getShapeType()) {

        case 1://Straight line
            ((Graphics2D) window).setStroke(new BasicStroke(getThickness(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            window.drawLine(getX1(), getY1(), getX2(), getY2());
            break;
        case 2://Rectangle
            if (getFilled())
                window.fillRect(getUpperLeftX(), getUpperLeftY(), getWidth(), getHeight());
            else {
                ((Graphics2D) window).setStroke(new BasicStroke(getThickness(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                window.drawRect(getUpperLeftX(), getUpperLeftY(), getWidth(), getHeight());
            }

            break;
        case 3://Oval
            if (getFilled())
                window.fillOval(getUpperLeftX(), getUpperLeftY(), getWidth(), getHeight());
            else {
                ((Graphics2D) window).setStroke(new BasicStroke(getThickness(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                window.drawOval(getUpperLeftX(), getUpperLeftY(), getWidth(), getHeight());
            }

            break;
        }
    }
}

static class PaintBoard extends JPanel implements MouseMotionListener, MouseListener {
    private static final long serialVersionUID = 1L;

    private boolean painting;
    private int prevX, prevY;
    private static Color canvasColour = Color.WHITE;
    private static int brushSize = 6;
    private static int brushType = 1;
    private static Color currentColour = Color.BLACK;

    private static LinkedList<brushLine> brushLines = new LinkedList<>();
    private brushLine currentBrushLine;

    private static LinkedList<Shape> shapes = new LinkedList<>();
    private static int shapeType = 0;
    private Shape currentShape = null;
    private static boolean filled;

    private JLabel mouseCoordinates = new JLabel("X: 0 pixels     Y: 0 pixels");

    public PaintBoard() {
        setSize(getWidth(), getHeight());
        setLayout(new BorderLayout());
        add(mouseCoordinates, BorderLayout.SOUTH);
        addMouseMotionListener(this);
        addMouseListener(this);
    }

    @Override
    public void paintComponent(Graphics board) {
        super.paintComponent(board);

        board.setColor(canvasColour);
        board.fillRect(0, 0, getWidth(), getHeight());

        ArrayList<brushLine> linesToDraw = brushLines.getArray();

        for (int i = linesToDraw.size() - 1; i >= 0; i--)
            linesToDraw.get(i).show(board);

        if (currentBrushLine != null)
            currentBrushLine.show(board);

        ArrayList<Shape> shapesToDraw = shapes.getArray();

        for (int j = shapesToDraw.size() - 1; j >= 0; j--)
            shapesToDraw.get(j).sketch(board);

        if (currentShape != null)
            currentShape.sketch(board);
    }

    public void mouseDragged(MouseEvent e) {
        mouseCoordinates.setText(String.format("X: %d pixels     Y: %d pixels", e.getX(), e.getY()));

        if (shapeType > 0) {
            currentShape.setX2(e.getX());
            currentShape.setY2(e.getY());
            repaint();
        } else {
            if (!painting)
                return;

            ((paintBrushLine) currentBrushLine).setX1(prevX);
            ((paintBrushLine) currentBrushLine).setY1(prevY);
            ((paintBrushLine) currentBrushLine).setX2(e.getX());
            ((paintBrushLine) currentBrushLine).setY2(e.getY());
            repaint();

            prevX = e.getX();
            prevY = e.getY();
        }
    }

    public void mouseMoved(MouseEvent e) {
        mouseCoordinates.setText(String.format("X: %d pixels     Y: %d pixels", e.getX(), e.getY()));
    }

    public void mouseClicked(MouseEvent e) {

    }

    public void mouseEntered(MouseEvent e) {

    }

    public void mouseExited(MouseEvent e) {

    }

    public void mousePressed(MouseEvent e) {
        switch (shapeType) {

        case 0://Curved line
            if (painting)
                return;

            prevX = e.getX();
            prevY = e.getY();

            currentBrushLine = new paintBrushLine(brushSize, brushType, currentColour, prevX, prevY, prevX, prevY);

            painting = true;
            break;
        default://Other shapes
            currentShape = new geometricShape(e.getX(), e.getY(), e.getX(), e.getY(), brushSize, currentColour, shapeType, filled);
            painting = false;
            break;
        }
    }

    public void mouseReleased(MouseEvent e) {
        if (shapeType > 0) {
            currentShape.setX2(e.getX());
            currentShape.setY2(e.getY());

            shapes.addFront(currentShape);

            currentShape = null;
            shapeType = 0;
            repaint();
        } else {
            if (!painting)
                return;

            ((paintBrushLine) currentBrushLine).setX2(e.getX());
            ((paintBrushLine) currentBrushLine).setY2(e.getY());

            brushLines.addFront(currentBrushLine);
            currentBrushLine = null;
            painting = false;
            repaint();
        }
    }
}
}

Класс LinkedList:

import java.util.ArrayList;

class LinkedList<T> {
private int numberOfNodes = 0; 
private ListNode<T> front = null;

// Returns true if the linked list has no nodes, or false otherwise.
public boolean isEmpty() {
    return (front == null);
}

// Deletes all of the nodes in the linked list.
// Note: ListNode objects will be automatically garbage collected by JVM.
public void makeEmpty() {
    front = null;
    numberOfNodes = 0;
}

// Returns the number of nodes in the linked list
public int size() {
    return numberOfNodes;
}

// Adds a node to the front of the linked list.
public void addFront( T element ) {
    front = new ListNode<T>( element, front );
    numberOfNodes++;
}

// Returns a reference to the data in the first node, or null if the list is empty.
public T peek() {
    if (isEmpty()) 
        return null;

    return front.getData();
}

// Removes a node from the front of the linked list (if there is one).
// Returns a reference to the data in the first node, or null if the list is empty.
@SuppressWarnings("unchecked")
public T removeFront() {
    T tempData;

    if (isEmpty()) 
        return null;

    tempData = front.getData();
    front = front.getNext();
    numberOfNodes--;
    return tempData;
}

@SuppressWarnings("unchecked")
public void removeEnd(T element) {
    ListNode<T> node=front;
    while(node.getNext() != null)
    {
        node = node.getNext();
    }
    node.setNext(new ListNode<T>((T)element, null));
}

// Return array filled with T objects
@SuppressWarnings("unchecked")
public ArrayList<T> getArray() {

    ArrayList<T> shapeArray=new ArrayList<T>();

    ListNode<T> node=front;
    while (node!=null)
    {
        shapeArray.add(node.getData());
        node = node.getNext();
    }

    return shapeArray;
}
}

Класс ListNode:

public class ListNode<T> {
private T data;
private ListNode next;

// Constructor: No reference to next node provided so make it null 
public ListNode( T nodeData ) {
    this( nodeData, null);
}

// Constructor: Set data and reference to next node.
public ListNode( T nodeData, ListNode nodeNext ) {
    data = nodeData;
    next = nodeNext;
}

// Accessor: Return the data for current ListNode object
public T getData() {
    return data;
}

// Accessor: Return reference to next ListNode object
public ListNode getNext() {
    return next;
}

// Mutator: Set new data for current ListNode object
public void setData( T newData ) {
    data = newData;
}


// Mutator: Set new reference to the next node object
public void setNext( ListNode newNext ) {
    next = newNext;
}
}

1 Ответ

0 голосов
/ 13 июня 2018

И ваши фигуры, и ваши линии хранят только начальную и конечную точки.

abstract static class Shape {
    private int x1, y1, x2, y2;
    private int thickness;
    private Color shapeColour;

Так как ваш метод рисования знает, что делать?Как он может нарисовать кривую, когда он знает только две точки?

Что вам нужно сделать:

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

Кроме того, добавьте некоторый код отладки, чтобы выяснить, какие значения использует ваш метод рисования, вы можете обнаружить, что причина, по которой вы видите только точки или маленькие линии, заключается в том, что значения для каждой фигуры / линии хранятся неправильно.

...