Layers

The layers feature is an ArrayList of BufferedImages. Unlike a static array, the ArrayList allows for objects, such as layers, to be created and deleted after initialization. I decided to use the BufferedImage class instead of its superclass, the Image class, due to its capability to implement transparency. The layers have to be transparent so that the layers painted underneath are still visible.

Layers.java -- Layers constructor
26
27
28
29
30
31
32
33
public Layers(PaintApp pLab) {  // Creates an ArrayList of BufferedImages to contain the layers and creates an initial layer
    paintLab = pLab;
    imageArray = new ArrayList<BufferedImage>();
     
    BufferedImage bImage = new BufferedImage(paintLab.getAppWidth(), paintLab.getCanvasHeight(), BufferedImage.TYPE_INT_ARGB);
    imageArray.add(bImage);     // Adds the first layer
    cLayerNum = 0;
}
 
				public Layers(PaintApp pLab) {  // Creates an ArrayList of BufferedImages to contain the layers and creates an initial layer
					paintLab = pLab;
					imageArray = new ArrayList<BufferedImage>();
					
					BufferedImage bImage = new BufferedImage(paintLab.getAppWidth(), paintLab.getCanvasHeight(), BufferedImage.TYPE_INT_ARGB);
					imageArray.add(bImage);     // Adds the first layer
					cLayerNum = 0;
				}
				

When the user decides to delete a layer, the layer cannot be deleted immediately. The requested layer is first set to a blank image to clear the canvas when repaint() is called.

Layers.java -- Deleting a layer
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public void deleteLayer() { // User deletes the current layer
    if ((cLayerNum != imageArray.size() - 1) || (cLayerNum > 0)) {  // If the current layer is not the only layer left
        BufferedImage bImage = new BufferedImage(paintLab.getAppWidth(), paintLab.getCanvasHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D buffg = (Graphics2D) bImage.getGraphics();
        buffg.fillRect(0, 0, paintLab.getAppWidth(), paintLab.getCanvasHeight());   // Creates a blank image the size of the canvas
         
        imageArray.set(cLayerNum, bImage);  // Sets the current layer to this blank image
        deleteLayer = true;
        changeLayer = true;
        paintLab.repaint(); // The blank image (user-requested deleted layer) clears the canvas and the other layers are redrawn on top
    }
    else {      // User cannot delete the only layer
        JOptionPane.showMessageDialog(null, "Sorry, but you cannot delete your only layer.");
        paintLab.repaint();
    }
}
 
				public void deleteLayer() { // User deletes the current layer
					if ((cLayerNum != imageArray.size() - 1) || (cLayerNum > 0)) {  // If the current layer is not the only layer left
						BufferedImage bImage = new BufferedImage(paintLab.getAppWidth(), paintLab.getCanvasHeight(), BufferedImage.TYPE_INT_ARGB);
						Graphics2D buffg = (Graphics2D) bImage.getGraphics();
						buffg.fillRect(0, 0, paintLab.getAppWidth(), paintLab.getCanvasHeight());   // Creates a blank image the size of the canvas
						
						imageArray.set(cLayerNum, bImage);  // Sets the current layer to this blank image
						deleteLayer = true;
						changeLayer = true;
						paintLab.repaint(); // The blank image (user-requested deleted layer) clears the canvas and the other layers are redrawn on top
					}
					else {      // User cannot delete the only layer
						JOptionPane.showMessageDialog(null, "Sorry, but you cannot delete your only layer.");
						paintLab.repaint();
					}
				}
				

When the repaint() calls paintLayers(), the blank layer is drawn with the other layers drawn on top. The layer's off-screen image is then deleted from the ArrayList. In order to prevent the other layers from constantly flickering while the user is painting, only the new current layer's graphics are updated.

PaintApp.java -- Updating the layers' graphics
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
public void paintLayers(Graphics2D g2Frame) {   // When a layer is created or deleted, or the user decides to switch to a different layer
    if (layersArray.deleteLayer) {  // A layer is deleted (can be any layer, not just the last layer in imageArray, that is not the only layer lef)
        g2Frame.drawImage(layersArray.getImageArray().get(layersArray.getcLayerNum()), 0, getMenuHeight(), this);       // Draws the blank deleted layer
            // Otherwise, the deleted layer will remain and is not erased on screen
         
        for (int k = 0; k < layersArray.getImageArray().size(); k++) {          // Then draws the rest of the layers in ascending order
            if (k!=layersArray.getcLayerNum()) {
                g2Frame.drawImage(layersArray.getImageArray().get(k), 0, getMenuHeight(), this);
            }
        }
         
        layersArray.deleteLayer = false;
        layersArray.getImageArray().remove(layersArray.getcLayerNum());         // Removes the blank deleted layer from imageArray
         
        if (layersArray.getcLayerNum() == layersArray.getImageArray().size())   // If the deleted layer was the last layer, then decrease cLayerNum
            layersArray.setcLayerNum(layersArray.getcLayerNum() - 1);           // If not, then cLayerNum is not decreased
            // eg If the third layer is deleted, then the next layer which used to be the fourth layer is now the third layer
         
        g2Frame.drawImage(layersArray.getImageArray().get(layersArray.getcLayerNum()), 0, getMenuHeight(), this);   // The current layer is drawn last for visibility
    }
    else // If you are not deleting a layer, update only the current layer's graphics.
            // If you constantly redrawing the other layers, then those other layers will flicker in the background
        g2Frame.drawImage(layersArray.getImageArray().get(layersArray.getcLayerNum()), 0, getMenuHeight(), this);
    }
     
    if (layersArray.changeLayer) {  // If a layer is created or deleted, or the user switches to the previous or next layer
        menuBar.changeLayerMenu();  // Layer status is updated
        layersArray.changeLayer = false;
    }
}
 
				public void paintLayers(Graphics2D g2Frame) {   // When a layer is created or deleted, or the user decides to switch to a different layer
					if (layersArray.deleteLayer) {  // A layer is deleted (can be any layer, not just the last layer in imageArray, that is not the only layer lef)
						g2Frame.drawImage(layersArray.getImageArray().get(layersArray.getcLayerNum()), 0, getMenuHeight(), this);       // Draws the blank deleted layer
							// Otherwise, the deleted layer will remain and is not erased on screen
						
						for (int k = 0; k < layersArray.getImageArray().size(); k++) {          // Then draws the rest of the layers in ascending order
							if (k!=layersArray.getcLayerNum()) {
								g2Frame.drawImage(layersArray.getImageArray().get(k), 0, getMenuHeight(), this);
							}
						}
						
						layersArray.deleteLayer = false;
						layersArray.getImageArray().remove(layersArray.getcLayerNum());         // Removes the blank deleted layer from imageArray
						
						if (layersArray.getcLayerNum() == layersArray.getImageArray().size())   // If the deleted layer was the last layer, then decrease cLayerNum
							layersArray.setcLayerNum(layersArray.getcLayerNum() - 1);           // If not, then cLayerNum is not decreased
							// eg If the third layer is deleted, then the next layer which used to be the fourth layer is now the third layer
						
						g2Frame.drawImage(layersArray.getImageArray().get(layersArray.getcLayerNum()), 0, getMenuHeight(), this);   // The current layer is drawn last for visibility
					}
					else {  // If you are not deleting a layer, update only the current layer's graphics.
							// If you constantly redrawing the other layers, then those other layers will flicker in the background
						g2Frame.drawImage(layersArray.getImageArray().get(layersArray.getcLayerNum()), 0, getMenuHeight(), this);
					}
					
					if (layersArray.changeLayer) {  // If a layer is created or deleted, or the user switches to the previous or next layer
						menuBar.changeLayerMenu();  // Layer status is updated
						layersArray.changeLayer = false;
					}
				}