Why can't I create an instance of a library from my own classes?

Why can't I create an instance of a library from my own classes?

In general, libraries require the user to create instances of the classes of the library. Often, the constructors of these classes require to give them ''this'' as parameter. For example, if I take the G4P library (aka. [http://www.lagers.org.uk/g4p/ GUI for Processing] or guicomponents), to create a button, you have to write:

btnSmile0 = new GButton(this, "smile.png", 3, 20, 270, 70, 70);

(from an example coming with the library). this is a Java keyword intended to give a reference to the current class.

When you run a sketch in Processing, it takes the code inside, and wraps it in a Java class, whose name is the name of your sketch, and which extends PApplet. This allows to access the methods of PApplet, like size() or line(), as if they where simple functions. Classes created inside a sketch have a similar direct access to these methods (and variables, like mouseX or width).

But classes created outside of this PApplet class, like library classes (or those put in .java files in your sketch folder), haven't such direct access. Actually, they don't have an access at all, unless they are provided with a reference to the instance of this class (ie. the running sketch). That's why they ask to provide such reference in the constructor, which they store and use to access to drawing functions, events, variables, etc. They do something like:

public class SomeClass
{
  private PApplet pa;

  // The constructor: same name as the the class, no return type
  public SomeClass(PApplet papp, int otherParam)
  {
    pa = papp;
    // etc.
  }

  public void drawStuff(int someParam)
  {
    // Call PApplet's methods
    pa.line( ... );
    // etc.
  }
}

Now, you might want to use a library from one of your classes. Something like:

class Stuff
{
  Stuff()
  {
    GButton btnSmile0 = new GButton(this, "smile.png", 3, 20, 270, 70, 70);
  }
}

If you run this, you hit a compilation error: The constructor GButton(yourSketchName.Stuff,String,int,int,int,int,int) is undefined.

The problem is that this refers to the current class. So, here, it refers to Stuff, and there is no GButton constructor accepting this "Stuff" as parameter. Result: you get an error, protesting that you gave a reference to some class that isn't a PApplet.

In other words, only the this available in Processing functions like setup(), draw() or keyPressed() can be used as parameter.

Fortunately, the solution is simple: adopt the same idiom as above for your own classes. Ie. make your constructor to get a PApplet parameter, fed with this from the main code, and pass pa (or whatever you call it) to the library class' constructor where this (the PApplet reference) is expected. More concretely, it would look like:

class Stuff
{
  Stuff(PApplet pa, String buttonName) // 'pa' here is equivalent to 'this' in Processing code
  {
    GButton btnSmile0 = new GButton(pa, buttonName, 3, 20, 270, 70, 70);
    // Etc. Save pa in an instance variable if you need it outside the constructor
  }
}

// Called from setup(), for example, like:
  Stuff stuff = new Stuff(this, "smile.png"); // Here, 'this' really refers to the PApplet

If you have other classes to instantiate from one of your class, you pass along the PApplet parameter to each constructor, a bit like a token / relay baton. Whenever you need a PApplet this, you use the pa field / parameter that have been transmitted via the constructor. The described process applies to each class needing such parameter.

Tagged:
Sign In or Register to comment.