Sorry, I was busy, no time for a detailed answer until the week-end...
So, let's go slowly.
A PGraphics is a PImage with additional methods (and perhaps fields) to draw upon the image.
You already manipulate a PGraphics without knowing it: when you do line(), you implicitly do g.line() where g is the default PGraphics used by Processing. All drawings go there, and at the end of draw(), it is copied on the screen.
Now, you can do your own PGraphics, of whatever size you want, that are, by default, not displayed. Sometime, you don't even want to display them, you just use them as a scratch pad (eg. finding if mouse is over a shape) or save them directly to disk (that's what we want to do).
ArrayList is relatively simple to use: it is really just an array that can automatically grow if filled up. It just have some specific syntax to add items and get them. I explained some details in
Why use ArrayList instead of array with append()? article.
Let's start simple and store the drawing in an array list. I won't use a PGraphics at first.
- ArrayList<Stroke> strokes = new ArrayList<Stroke>();
- boolean bNewLine = true;
-
- void setup()
- {
- size(360, 480);
- smooth();
- }
-
- void draw()
- {
- background(255);
- if (mousePressed)
- {
- Stroke s = new Stroke(mouseX, mouseY, bNewLine);
- strokes.add(s);
- bNewLine = false;
- }
- else
- {
- bNewLine = true;
- }
-
- Stroke ps = null;
- for (Stroke s : strokes)
- {
- if (!s.bNewLine)
- {
- line(ps.x, ps.y, s.x, s.y);
- }
- // Else, don't draw a line from the previous stroke
-
- // This point is the starting point of the next line
- ps = s;
- }
- }
-
- class Stroke
- {
- int x, y;
- boolean bNewLine;
- Stroke(int _x, int _y, boolean _b)
- {
- x = _x;
- y = _y;
- bNewLine = _b;
- }
- }
I used a simple class that's just an easy way to store several related values together.
If you really have memory problems, we can reduce the memory usage even further (by dropping the storage of the boolean), but it is a bit more advanced. Since it is still quite simple, I show it as it is a nice illustration of OO coding:
You can still use the first version if you feel more comfortable with it, they are functionally equivalent.
- ArrayList<Stroke> strokes = new ArrayList<Stroke>();
- boolean bNewLine = true;
- void setup()
- {
- size(360, 480);
- smooth();
- }
- void draw()
- {
- background(255);
- if (mousePressed)
- {
- Stroke s; // Declare to the interface
- if (bNewLine)
- {
- s = new NewLineStroke(mouseX, mouseY);
- }
- else
- {
- s = new ContinuationStroke(mouseX, mouseY);
- }
- strokes.add(s);
- bNewLine = false;
- }
- else
- {
- bNewLine = true;
- }
- Stroke ps = null;
- for (Stroke s : strokes)
- {
- if (!s.startsNewLine())
- {
- line(ps.getX(), ps.getY(), s.getX(), s.getY());
- }
- // Else, don't draw a line from the previous stroke
- // This point is the starting point of the next line
- ps = s;
- }
- }
- // The interface defines what methods MUST be implemented by the classes using it
- // If we define an array list storing Stroke, we can put in it anything implementing this interface,
- // and be confident we can use these methods on these objects.
- interface Stroke
- {
- /** @return true if we need to start a new, disconnected line from here. */
- boolean startsNewLine();
- // Getters
- int getX();
- int getY();
- }
- // Implementation common to both concrete classes
- // By making it abstract, we cannot instantiate it, cannot be used with 'new'
- abstract class BaseStroke implements Stroke
- {
- // Protected: sub-classes can access them
- protected int x, y;
- //@Override -- Processing doesn't understand annotations yet
- // The above indicates this method is required by the interface we implement
- int getX() { return x; }
- //@Override
- int getY() { return y; }
- // startsNewLine() isn't here, which is legal because this class is abstract
- }
- // Here, we inherit BaseStroke, so we can use what it defined
- class NewLineStroke extends BaseStroke
- {
- public NewLineStroke(int _x, int _y)
- {
- x = _x;
- y = _y;
- }
- //@Override
- public boolean startsNewLine()
- {
- return true; // Specific to this implementation
- }
- }
- class ContinuationStroke extends BaseStroke
- {
- public ContinuationStroke(int _x, int _y)
- {
- x = _x;
- y = _y;
- }
- //@Override
- public boolean startsNewLine()
- {
- return false; // Specific to this implementation
- }
- }