Capturing keyEvent in own class: registerMethod()

edited December 2017 in Questions about Code

I was looking at the way to create my own that manages key events internally. So, it is required to intercept key events. This is my reference post: https://forum.processing.org/two/discussion/comment/104394/#Comment_104394 and the link to the PApplet's source code for reference PApplet.handleEvent(): I am using almost the same code as from the PApplet. I see redundancy. My question is, is this the proper way to do this?

Kf

import processing.core.*;
import processing.event.*;

TestClass aux;

void setup() {
  size(640, 480);
  fill(150);
  aux=new TestClass(this);
}

void draw() {
  background(0);
  if (frameCount%90==0) { 
    println(aux); 
    fill(random(50, 200));
  }
}


public class TestClass {
  int mX, mY;
  PApplet p;

  TestClass(PApplet pa) {
    p=pa;
    registerMethod("draw", this);
    //registerMethod("keyPressed", this);
    registerMethod("keyEvent", this);
  }

  public void keyEvent(KeyEvent event) {
    print("KE now  --> ");

    if (!keyRepeatEnabled && event.isAutoRepeat()) return;

    keyEvent = event;
    char key2 = event.getKey();
    keyCode = event.getKeyCode();

    switch (event.getAction()) {
    case KeyEvent.PRESS:     
      this.keyPressed( key2);      
      break;
    case KeyEvent.RELEASE:      
      this.keyReleased( key2);
      break;
    case KeyEvent.TYPE:
      this.keyTyped( key2);
      break;
    }
  }

  public void keyPressed(char inkey) {
    println("KE pressed!"+inkey);
  }

  public void keyReleased(char inkey) {
    println("KE releasedd!"+inkey);
  }

  public void keyTyped(char inkey) {
    println("KE typed!"+inkey);
  }

  public void draw() {
    ellipse(width>>1, height>>1, width>>2, height>>2);
  }

  @Override
    String toString() {
    String ss="";
    ss+="Mouse pointer: \t" +mX+"\t"+mY+"\n";   
    return ss;
  }
}

Answers

  • Answer ✓

    Looks good to me but you should use the p variable inside the class. For instance line 67 should be

    p.ellipse(p.width>>1, p.height>>1, p.width>>2, p.height>>2);

    Line 27 should be

    registerMethod("draw", this);

    and so on.

    The only reason it works at the moment is because the class TestClass is an inner class and has access to the attributes of its parent. If you ever make TestClass a top level class then this will not be true and your code will fail.

    You can make it top level by either

    1) Changing line 21 to public static class TestClass {, or by

    2) Creating a new Java tab called TestClass.java and putting the class code in there.

  • edited December 2017 Answer ✓

    You can make it top level by either: Changing line 21 to public static class TestClass {, ...

    Declaring a nested class w/ static doesn't remove the fact it is still a nested class!

    Although it is indeed correct to say that a static nested class behaves very much like a top-class; which is implicitly static too btW. ;;)

  • Answer ✓

    ... but you should use the p variable inside the class.

    Or remove that completely! ;)) Those this. aren't needed either. >-)

  • Thxs @quark and @GoToLoop. I will make it a top class indeed. I will proceed as it is then as it is good enough for me. Quick question regarding refactoring. If there is a function from the PApplet that I want to change, I have to extend from this class or could I embedded the affected function into the current instance? For example, this is a common example I have seen before, but with a field:

    Frame get_frame() {
      Frame frame = null;
      try {
        Field f = ((PSurfaceAWT) surface).getClass().getDeclaredField("frame");
        f.setAccessible(true);
        frame  = (Frame) (f.get(((PSurfaceAWT) surface)));
      }
      catch(Exception e) {
        println(e);
      }
      return frame;
    }
    

    Could I do something similar with but with a function: loadImage()?

    Kf

  • edited December 2017 Answer ✓

    It is very easy to redefine any public or protected class in PApplet provided it has not been marked as final.

    You need to create a method with the same name, same parameters and same return type as the original. For instance the loadImage method in PApplet has a single String parameter for the filename and a return type of PImage.

    This sketch shows how to override the loadImage method in PApplet

    PImage img;
    
    void setup() {
      size(400, 400);
      img = loadImage("No chance");
    }
    
    public PImage loadImage(String filename) { 
      println("loadImage method overridden");
      return null;
    }
    

    The output is "loadImage method overridden".

    This works because the sketch code is wrapped up into a class that extends PApplet (so won't work in your TestClass).

    You can also refine the method like this

    public PImage loadImage(String filename) { //, Object params) {
      PImage img = super.loadImage(filename); // call the method in PApplet
      println("\nloadImage method refined");
      return img;
    }
    
  • @quark I tried the option to overload loadImage before. I have this idea of creating a lib or a tool that will allow to handle when loadImage returns null. In testing cases (for instance, running many post in the forum), you don't have the image available in the post. Having a tool to override null and call createImage to generate an object... removes the hassle of setting the environment... ok, I wil be saving some clicks, some copy and paste and code editing. I don't see a way to manage this from a top class (yes, to override the PApplet...). I will keep thinking about this. Thxs.

    Kf

  • Answer ✓

    I can see where you are coming from. There are many discussions on the forum with code using loadImage but without the images available so can't be tested.

    Even if you could somehow override loadImage and then use createImage orcreateGraphics to make PImage if the image-file can't be found, you wouldn't know what size to create it.

  • edited December 2017

    ... of creating a lib or a tool that will allow to handle when loadImage() returns null.

    If that library's purpose is to @Override any of the class PApplet's methods, that's a lost cause! :-<

    B/c even if we'd import such library into our sketches, and we'd keep on directly invoking any PApplet's methods the usual way, our code would still use the original methods, not those from the imported library! :-O

    In order to get access to the "hacked" subclass PApplet, we'd need to instantiate it w/ new.
    Then ignite it w/ runSketch(). #:-S

    But then, another canvas window would show up as well.
    And we'd need to prefix the whole "hacked" API w/ the variable holding its instance. :ar!

Sign In or Register to comment.