I am working on a paint app project and am working on an "undo" function. I have created an undrawHandler ActionEvent method to handle this and when I run my code my whole canvas is cleared instead of removing the last shape in the array list and I am getting an error: Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Cannot invoke "Circle.draw(javafx.scene.canvas.GraphicsContext)" because "this.shape" is null
Here is my code:
import javafx.application.Application;
import javafx.css.Size;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.control.TextField;
import javafx.scene.text.*;
import java.util.ArrayList;
public class PaintApp extends Application {
// TODO: Instance Variables for View Components and Model
private ArrayList<GeometricObject> shapes;
private GraphicsContext gc;
private TextField rField;
private TextField gField;
private TextField bField;
private TextField brushSize;
boolean drawCircle = true;
private ActionEvent e;
private Circle shape;
// TODO: Private Event Handlers and Helper Methods
private void mouseEventHandler(MouseEvent me) {
int red = 0;
int blue = 0;
int green = 0;
int size = 10;
String col;
// location for drawing
double x = me.getX();
double y = me.getY();
// color for drawing
try {
red = Integer.parseInt(rField.getText());
blue = Integer.parseInt(bField.getText());
green = Integer.parseInt(gField.getText());
size = Integer.parseInt(brushSize.getText());
// Check all these values are between 0 and 255 - if not update error label
}catch(NumberFormatException e)
{
// Update error label on screen to notify user of problem
return; // exit the method, don't keep going
}
// going to draw
GeometricObject shape;
if (drawCircle)
shape = new Circle(x,y, Color.rgb(red, green, blue), size);
else
shape = new Square(x,y, Color.rgb(red, green, blue), size);
shape.draw(gc);
shapes.add(shape); // add the shape to my arraylist to keep track of order drawn
}
private void undrawHandler(ActionEvent e)
{
int index = shapes.size() - 1; // remove the last item from the arraylist
shapes.remove(index);
gc.setFill(Color.WHITE);
gc.fillRect(0,0,800,400); // redraw the white rectangle ( the background)
// redraw the canvas with everything else
// redraw all shapes in the arrayList (loop)
if (!shapes.isEmpty())
{
shape.draw(gc);
}
}
/**
* This is where you create your components and the model and add event
* handlers.
*
* @param stage The main stage
* @throws Exception
*/
@Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene scene = new Scene(root, 800, 500); // set the size here
stage.setTitle("FX GUI Template"); // set the window title here
stage.setScene(scene);
// TODO: Add your GUI-building code here
// 1. Create the model
shapes = new ArrayList<>();
// 2. Create the GUI components
Canvas c = new Canvas(800,400); // used for Mouse events
gc = c.getGraphicsContext2D();
rField = new TextField();
gField = new TextField();
bField = new TextField();
brushSize = new TextField();
Label col = new Label("Color:");
Label size = new Label("Size:");
Button draw = new Button("Draw");
Button undraw = new Button("UnDraw");
Button circle = new Button("Circle");
circle.setOnMousePressed((event) -> {
drawCircle = true;
});
Button square = new Button("Square");
square.setOnMousePressed((event) -> {
drawCircle = false;
});
undraw.setOnMousePressed((event) -> {
undrawHandler(e);
});
// 3. Add components to the root
root.getChildren().addAll(rField, gField, bField,col,draw, circle, square,brushSize,size,undraw, c);
// 4. Configure the components (colors, fonts, size, location)
circle.relocate(10,430);
square.relocate(65,430);
rField.relocate(465,430);
rField.setPrefWidth(50);
bField.relocate(515,430);
bField.setPrefWidth(50);
gField.relocate(565,430);
gField.setPrefWidth(50);
size.relocate(340,430);
brushSize.relocate(370,430);
brushSize.setPrefWidth(50);
col.relocate(430,430);
draw.relocate(625,430);
undraw.relocate(675,430);
// 5. Add Event Handlers and do final setup
gc.setFill(Color.WHITE);
gc.fillRect(0,0,800,400);
c.addEventHandler(MouseEvent.MOUSE_PRESSED, this::mouseEventHandler);
c.addEventHandler(MouseEvent.MOUSE_DRAGGED, this::mouseEventHandler);
// 6. Show the stage
stage.show();
}
/**
* Make no changes here.
*
* @param args unused
*/
public static void main(String[] args) {
launch(args);
}
}