How do you call a method in your main sketch from a class with arguments?

Hey,

my main sketch has a method to hide some of the UI, if any instance of another class does something. Now, from within my class instances I manage to call this method in the main sketch with PApplet.method(), but I struggle to find a straight forward way of calling this main sketch method with arguments. Ideally, the argument I'd like to pass in is the instance of my class itself.

Simplifying pseudo code example:

Main sketch:

Foobar foo = new Foobar(this);
Foobar bar = new Foobar(this);

void hideUI(Foobar which) {
    hideSomeStuff();
    if (which == foo) {
       // 't was foo that called
    }
}

Foobar:

Foobar(PApplet parent) {
    parent.method("hideUI"); // here is the problem, I can't pass "this" back up to the main sketch
}

The problem is because I use the Processing IDE when I pass "this" to the Foobar instance on creation I can actually only access it as a PApplet instance, and thus there is no way of calling "parent.hideUI(this)" directly, because PApplet does not have such a function. Do I need to switch to coding this with Eclipse and making my main sketch a class that extends PApplet or is there a way around it and doing this with the Processing IDE?

Any ideas welcome, also restructuring the whole thing if there is a smarter way to get to the same result.

Cheers,
k.

Answers

  • Thanks for the, rather cryptic, answer. So you are suggesting I attach a string identifying the instance and then create a function for every of the instances?

    For two reasons this won't work: - My instances are dynamically generated (and in theory unlimited) - I have many of these kind of delegation calls to my main sketch

    This will need some more programmatic solution, I think.

  • edited February 2016

    quote:

    The problem is because I use the Processing IDE when I pass "this" to the Foobar instance on creation I can actually only access it as a PApplet instance

    you can make a global var PApplet thisSketchThis iirc

    and in setup() say thisSketchThis=this; and in the class or whereever just use thisSketchThis, then you have a this that refers to the sketch itself even inside the class.

    remark

    I don't like

    PApplet.method()
    

    very much. Is it just me?

    Isn't PApplet dead with version processing 3?

    Alternatively you could write your own executeCommand function with global scope

    void executeCommand (int commandID) {
    
        switch (commandID) {
    
        }
    
    }
    

    you could even name the commands there are :

    final int commandHideUIMain = 0; 
    final int commandHideUIExpert = 1; 
    

    and pass them to executeCommand() as a parameter

    void executeCommand (int commandID) {
    
        switch (commandID) {
    
            casecommandHideUIMain: 
                //
                break; 
    
            case commandHideUIExpert:
                //
                break; 
    
        }
    
    }
    
  • Hey, thanks for your answer Chrisir.

    Even if I store the reference to "this" in a variable in the main sketch, and then assign it and pass it in the class instantiation, the problem is the same, no? In the other class I can only cast it as PApplet, and consequently only use PApplet methods, like "method("")". And this won't change that my custom functions from the main sketch are not available to the "this" object, as it is still just a PApplet, not my extended main sketch.

    I understand your skepticism about the PApplet, but the executeCommand function changes nothing per se, it's just a method in my main sketch like my "pseudo" hideUI() - of course I could combine different actions into one "executeCommand" routine, but I need to anyway separate the actions they take (when they are more complex).

  • So I am still looking for a solution to this that let's me pass arguments back to the main sketch. For now, one workaround for at least differentiating the instances of my class on calling goes as follows:

    Use a single instance of a new class, call it "Delegator". This single instance get's passed to every instance of the "Foobar" class in the constructor in the main sketch. The "Delegator" then has a method, which calls the main sketch with ".method()", like before, but in this method it also stores the caller (which get's passed in, i.e. the instance of Foobar that's calling". Delegator further has a function to retrieve the last stored caller.

    Like this, in whatever function I have in my main sketch, when it get's called by proxy from Foobar via Delegator, I can query the single Delegator instance and check which instance of Foobar was the last caller.

    Obviously, this isn't very clean. Any better suggestions on how to do this? This workaround I could somehow pass arguments still in as an array of object or something, but it would get more and more obscure.

    Any ideas?

  • Function method(""), just like thread(""), doesn't have parameters and doesn't return anything.
    https://Processing.org/reference/thread_.html

    Another big limitation is that any called method thru' them gotta directly belong to the main sketch.
    Therefore we can't use them to call methods from another class

    Actually method("") isn't an "official" Processing API function.
    method("") is used internally by thread("") in order to call a sketch function by its String name, using a technique called reflection.

    If you really need to pass arguments to any method, you're gonna need to come up w/ your own customized method() of your own. See Java's Class & Method classes:

    http://docs.Oracle.com/javase/8/docs/api/java/lang/Class.html
    http://docs.Oracle.com/javase/8/docs/api/java/lang/reflect/Method.html

    Some forum threads about getMethod():
    https://forum.Processing.org/two/discussions/tagged?Tag=getmethod()

  • edited February 2016 Answer ✓

    @kontur: I don't get what you want.

    You can call a function with global scope (same scope level as draw()) from any class. You can also pass parameters to it. You don't need method() or anything.

  • Oh wow, I so was overthinking this.

    I just assumed (read: was blind enough) in accordance with OOP that I cannot simply call some global method from my main sketch in any other processing class I got. When in fact, they are all "nested" under it, so all processing classes got access to the main sketch's methods as they are public.

    Wow, fail. Sometimes you just don't see the forrest with all the trees.

  • wow, glad you say that.

    I was feeling stupid stating the obvious but that was the right thing to do after all...

    ;-)

  • Oh indeed. Now it seems so obvious.

    Then again, I was staying more true to the OOP paradigm than Processing itself (which is good for beginners and quick prototyping, I suppose); it just didn't occur to me that my sketch main class would somehow be "in global" space - I tried to force pass in a reference to it when really it is "all there is around" the processing classes you create. I suppose this would only be different if I create my classes as actual "Foobar.java" documents, and they then lose this comfortable "processing padding" of being able to access the main sketch methods from global.

    Solved. Thanks again.

  • edited February 2016

    true, processing makes it easy....

    probably it's wise to put as much into classes as you can.

    Except the setup, draw, keyPressed, mousePressed etc. etc.

    remark

    but you can also in Java access a method in a class from another class with params like

    in the class Car you could say

    cyclist.hit(fromSide); 
    

    or whatever

  • Oh yea, exactly my thinking; ergo you need a reference to "cyclist" available to execute the method on inside your Car code, which I didn't. (There "is" no main sketch instance I could pass in, because passing in "this" from the main sketch you can only cast to PApplet, not actually reference my extended class of PApplet with all the methods you define in the main scope.)

    Interesting :))

  • edited February 2016 Answer ✓

    Up till now I was completely puzzled why would you choose the harder way! @-)
    I'm not here to question OPs' decisions, even if they're incomprehensible, but try to guide them to implement it. 8-|

    ... in accordance with OOP that I cannot simply call some global method from my main sketch...

    When in fact, they are all "nested" under it,...

    By default all classes we define in Processing's IDE (PDE) are nested to the sketch.
    Which in turn is the only actual top PApplet class for our whole program.
    We can escape from that by creating tabs w/ suffix ".java" though.

    Indeed for OOP it is "sinful" to directly access some unrelated class from another class.
    But as you had found out by now, all classes we define in PDE automatically pseudo-inherits everything from the enclosing sketch class, which behaves very similar to those famous JS closures.

    However if you prefer to strictly adhere to OOP, there are better ways than to tame Processing's method(), which was made for simpler cases btW.

    The sketch's top class inherits from Processing's PApplet.
    That's why we can pass its reference as PApplet.

    However, if we implement new methods, like your hideUI(), PApplet isn't enough to access that.
    We're gonna need the exact name of the PApplet subclass. Which is always the name of the 1st tab in the PDE.

    Here's a silly sample demoing it. Since I haven't saved the sketch yet, the 1st tab is named "sketch_160217a".
    Therefore that's the name of the actual top class. Check it out:

    // forum.Processing.org/two/discussion/14943/
    // how-do-you-call-a-method-in-your-main-sketch-
    // from-a-class-with-arguments
    
    // GoToLoop (2016-Feb-17)
    
    void setup() {
      new Foobar(this).test();
      exit();
    }
    
    void hideUI(final Foobar which) {
      println(which);
    }
    
    class Foobar {
      final sketch_160217a p;
    
      Foobar(PApplet pa) {
        p = (sketch_160217a) pa;
      }
    
      void test() {
        p.hideUI(this);
      }
    }
    
  • Hey GoToLoop,

    thanks for the answer still! This is in fact what I was looking for, even though it's quite crude to hardcode the name of the Sketch into the other classes; but it does what I was trying to do indeed!

    Which is the more "neat" way to do it is of course up for debate, but thank you very much for showing me this neat trick with the Sketch name as the actual class name of the extended PApplet! :)

  • edited February 2016

    Glad you've liked. A last tip: Hit CTRL+SHIFT+E to export the saved sketch.
    Then take a look at the generated ".java" file there.
    You're gonna see the actual valid Java source which corresponds to all our ".pde" tabs. :D

Sign In or Register to comment.