如何使用LinkedList和MouseListeners在屏幕上绘制曲线?

时间:2018-06-13 01:36:11

标签: java linked-list awt mouselistener mouse-listeners

我是Java的新手,至于我班级的最终项目,我正在开发一个绘图应用程序,使用户能够绘制丰富的曲线和常见的几何形状,如矩形和椭圆形,用户也可以撤消它们的形状绘图。

我的应用程序在形状绘制方面表现良好。当我想绘制形状时,我想要绘制的形状存储在LinkedList中,将被调用以在屏幕上绘制形状当我应用此LinkedList概念在屏幕上绘制曲线时。我修改了形状绘制代码来绘制曲线。我碰到了一个问题;我得到的结果是little dots on the screen.如果我试图复制类似的代码来绘制绘制曲线的形状,我会得到直线而不是曲线。

我认为这个问题与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 :(得分:0)

您的形状和线条都只存储起点和终点。

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

那么你的绘画方法怎么知道怎么做?当它只知道两点时,它如何绘制曲线?

您需要做什么:

一旦你完成了形状,你需要做一些数学计算,根据前一个和下一个段的坐标计算出每个弧的半径和坐标,然后在你的绘画方法中,你可以画很多很小的线条使它看起来很光滑。

另外,添加一些调试代码以找出您的绘制方法使用的值,您可能会发现只看到点或小线的原因是因为每个形状/线的值未正确存储。