Is there a way to set a new draw handler?

edited August 2015 in Questions about Code

Below is a brief example of my problem. The draw function acts completely different depending on the mode. In the real case, there are a lot more modes and things area lot more complicated than drawing a shape. I don't want my draw loop to run through a bunch of nested booleans every time it executes. Ideally, the draw function for that mode should be set when the user changes mode instead of checking a bunch of booleans 60 times a second. In C I'd use a pointer to a function and reset it when the mode changes. How would I get the same function in Processing? I know with a gp4 window you can myWindow.addDrawHandler(), but I think you can only do it at the setup. I need a way to change the main draw loop dynamically.

PImage img;
int CIRCLE = 0;
int RECTANGLE = 1;
int mode = CIRCLE;

void setup(){
size(200,200);
img = createImage(200,200,RGB);
}
void draw(){
     background(150);
     if( mode == CIRCLE)
          ellipse(100,100,30,30);
     if( mode == RECTANGLE)
          rect(75,75,50,50);
}
void keyPressed(){
     if(key == ' '){
          if(mode == CIRCLE)
               mode = RECTANGLE;
          else mode = CIRCLE;
     }
}

Answers

  • To clarify, I would like the above program not to have to check the mode 60 times a second. I would like it go to the draw function that draws the proper shape, the function that was set when the user changed modes.

  • edited August 2015 Answer ✓

    Even in C, I'd suggest that you test whether or not an if statement is slower than a function pointer call. With that in mind, your best bet at emulating a C function pointer is a Java interface.

    For example:

    MyFunctor drawAction;
    
    void setup() {
      size(200, 200);
      drawAction = new DrawRect(); // You'd set this either to DrawCircle or DrawRect.
    }
    
    void draw() {
      drawAction.myMethod();
    }
    
    interface MyFunctor {
      void myMethod(); //Force modes to implement this method.
    }
    
    class DrawCircle implements MyFunctor {
      void myMethod() {
        ellipse(100, 100, 30, 30);
      }
    }
    
    class DrawRect implements MyFunctor {
      void myMethod() {
        rect(75, 75, 50, 50);
      }
    }
    

    Again, I recommend you test whether or not this is a more effective approach, but this is how you'd do it in Java.

    To answer your title question: No. You do not have that freedom in Processing, as far as I know. Any decision-making in your code must be made in the callback functions provided by Processing.

  • edited August 2015

    Actually Processing provides us many other tricks, but undocumented. 8-X
    For example, we can use method(""), passing the name of the calling function as a String: *-:)

    // forum.processing.org/two/discussion/12265/
    // is-there-a-way-to-set-a-new-draw-handler
    
    // GoToLoop (2015-Aug-26)
    
    static final String CIRCLE = "circle";
    static final String RECTANGLE = "rectangle";
    String mode = CIRCLE;
    
    void setup() {
      size(200, 200, JAVA2D);
      smooth(4);
    
      noLoop();
      frameRate(10);
    
      rectMode(CENTER);
      ellipseMode(CENTER);
    
      fill(#FFFF00);
      stroke(0);
      strokeWeight(2.5);
    }
    
    void keyPressed() {
      if (key == ' ')  mousePressed();
    }
    
    void mousePressed() {
      mode = mode == CIRCLE? RECTANGLE : CIRCLE;
      redraw = true;
    }
    
    void draw() {
      background(0250);
      method(mode);
    }
    
    void circle() {
      ellipse(width>>1, height>>1, width>>1, height>>1);
    }
    
    void rectangle() {
      rect(width>>1, height>>1, width>>1, height>>1);
    }
    
  • GoToLoop has already suggested what I was going to say: use method().

    You might also be interested in this thread: http://forum.processing.org/two/discussion/comment/46717/

  • edited August 2015

    Although method("") is both succinct & cool, it's magnitudes slower than regular if () blocks due to its internal use of "reflection". :(
    @MenteCode's approach is both faster and more Java-ish streamlined.
    Here's a variant of it relying on anonymous instantiation of some base interface though: :ar!

    // forum.processing.org/two/discussion/12265/
    // is-there-a-way-to-set-a-new-draw-handler
    
    // GoToLoop (2015-Aug-26)
    
    static interface Display {
      void display();
    }
    
    final Display CIRCLE = new Display() {
      void display() {
        ellipse(width>>1, height>>1, width>>1, height>>1);
      }
    };
    
    final Display RECTANGLE = new Display() {
      void display() {
        rect(width>>1, height>>1, width>>1, height>>1);
      }
    };
    
    Display mode = CIRCLE;
    
    void setup() {
      size(200, 200, JAVA2D);
      smooth(4);
    
      noLoop();
      frameRate(10);
    
      rectMode(CENTER);
      ellipseMode(CENTER);
    
      fill(#FFFF00);
      stroke(0);
      strokeWeight(2.5);
    }
    
    void keyPressed() {
      if (key == ' ')  mousePressed();
    }
    
    void mousePressed() {
      mode = mode == CIRCLE? RECTANGLE : CIRCLE;
      redraw = true;
    }
    
    void draw() {
      background(0250);
      mode.display();
    }
    
  • Right. Yes. Don't actually use method(). You could, but it is probably slower.

    Inherit from a base interface. Yes. Actually do that.

    Hopefully this answer is not confusing.

  • Oh yeah. In case anyone's confused, functors are a C++ idiom. They're structs/classes which mimic regular functions, but they're easily stored in a variable.

    Which is why you see said name in my example.

  • The idea is the slowness of the operation should happen during the choice of mode. Thats a one second mouse choice anyway. It would also make the code more readable. I understand if's / elses and booleans if only a few things are changing, but when the whole function changes, it doesn't make sense to have it deeply embedded in conditions. It begins to look chaotic. I'm going to try the drawAction(); idea.

Sign In or Register to comment.