selectInput(); in a class in Eclipse, callback not found

edited January 2014 in Questions about Code

Hi masterminds,

I started using Processing in Eclipse, and I'm trying to load a file using the selectInput() function. This function should automatically bring the selected file to a callback function (named fileSelected() ), where it is processed further. See reference: http://www.processing.org/reference/selectInput_.html

In my code however, it says fileSelected() cannot be found.

I'm combining it with a function from a library called iGeo, but I tried it without that too, so that is not the problem.

This is my code in the main class:

    public void setup() {
        size(displayWidth-50, displayHeight-150, IG.GL );
        IG.bg(0);
        IG.perspective();
        IG.focus();

        Mesh mesh = new Mesh(this);
        mesh.open();
          }

And this is the mesh class:

import java.io.File;
import javax.swing.JFileChooser;
import processing.core.PApplet;
import igeo.*;

public class Mesh {

  PApplet parent; 

  Mesh(PApplet p) {
        parent = p;
      }

  void open() {
      parent.selectInput("Select a mesh to process:", "fileSelected");
      }


  void fileSelected(File selection) {
      if (selection == null) {
        System.out.println("Window was closed or the user hit cancel.");
      } else {
          System.out.println("User selected " + selection.getAbsolutePath());
          String path = selection.getAbsolutePath();
          IG.open(path);
      }
          }
}

I hope someone can help out!

Answers

  • edited January 2014

    Hmmm... selectInput(), like all Processing's API, is bound (inherited) to the class
    which extends and instantiates PApplet by statically invoking PApplet.main().

    Thus, any callbacks should dwell inside that very same igniting class,
    since that's the only reference pointer they know.

    How can selectInput() suppose to know the reference(s) for your own class(es)
    in order to callback its(their) method(s) anyways? :-?

  • edited January 2014

    I'm not sure if I completely understand what you mean, but I've tried to call fileSelected with "Mesh.fileSelected()", and also, I've tried to make the functions public, but that both didn't work.. Was that what you meant?

    Sorry if I'm saying stupid things, I'm still getting used to this hierarchy in which PApplet is a class itself..

    Thanks for your answer anyway!

  • edited January 2014

    It took me a while to comprehend how both Processing & Java work.
    And finally how Processing interacts w/ Java as a framework.

    A Processing's program 1st has to pass through a pre-compiler to turn it into a valid Java source.
    If you hit CTRL+E inside Processing's IDE, you're gonna get a real ".java" source file.
    Then you'll realize that the whole program is wrapped up as 1 class which extends PApplet.
    Most probably you already know all of that since you're using Eclipse anyways. O:-)

    Most interesting part is the auto-generated main() starting point.
    That's the place which instantiates & ignites the whole Processing's framework API thru' PApplet.main()!

    After that initialization process is completed, it finally calls back our custom setup().
    Then it creates a canvas as a java.awt.Frame, and starts calling draw() at default frameRate(60). (*)
    And also any other event callback!

    For our own classes to communicate w/ that running instance and its Frame canvas, we need its reference.
    That's what you do within your Mesh's constructor -> Mesh(PApplet p) { parent = p; }

    In particular for selectInput()/selectFolder(), it assumes that the callback method
    is within the running instance of the main Processing's class.
    Nevertheless, those functions are also overloaded to accept different # of arguments:

    • selectInput(prompt, callback)
    • selectInput(prompt, callback, file)
    • selectInput(prompt, callback, file, callbackObject)
    • selectInput(prompt, callbackMethod, file, callbackObject, parent)

    There's no detailed instructions how to use those alternative ways.
    But I bet it's either "callbackObject" or "parent" parameters where we can specify the reference
    of another object where lies our custom callback method! :ar!

    Good luck! %%-

    processing.org/reference/selectInput_.html
    processing.org/reference/selectFolder_.html
    processing.org/reference/selectOutput_.html

  • Yes, try:

    parent.selectInput("Select a mesh to process:", "fileSelected", null, this);
    
  • Thank you so much for the explanation! Clears things up a bit :) What I can conclude from it is that there are two options:

    1. What Phil.ho said (thanks!) - stating it should happen in this class.
    2. Calling the callback function like Mesh.fileSelected() (or mesh.fileSelected() - not sure), - which also states it should happen in this class.

    However, both still give 'fileSelected() could not be found'.

    I started looking for an alternative in java, to avoid all the complicated processing references, and solved it like this:

    public class Mesh {
          PApplet parent; 
    
          Mesh(PApplet p) {
                parent = p;
              }
    
          void open() {
             final JFileChooser fc = new JFileChooser();
             int returnVal = fc.showOpenDialog(parent);
    
             if (returnVal == JFileChooser.APPROVE_OPTION) {
                  File file = fc.getSelectedFile();
                  String path = file.getAbsolutePath();
                  IG.open(path);
              } else {
                  System.out.println("No file was selected; start again.");
              }
          }
    

    Which works, yay! Although.. almost. It gives one problem, which is that it opens the dialog twice, even if a file was selected the first time. If I press cancel the second time, it works alright though.

    Any thoughts?

  • edited August 2014

    Nice you've found a more Java-ish solution. But I'm afraid you haven't quite got what we meant! :-<
    I'll try to use less complicated stuff like how Processing interacts w/ Java this time! O:-)

    When we use selectInput()/selectFolder()/selectOutput() w/ just 2 arguments, it's always assumed that
    our callback method lies within the top running sketch rather than some other class of ours! @-)

    As @PhiLho stated, we gotta use the overloaded version w/ 4 (or perhaps w/ 5 too) arguments!

    I've installed the IGeo library and make some tweaks by myself. Check it out: :bz

    P.S.: (v2.1) -> checks for valid selected file's extension.

    IGeoMesh.pde:

    /**
     * IGeo Mesh (v2.13)
     * by  Tessa (2014/Jan)
     * mod GoToLoop
     *
     * forum.processing.org/two/discussion/2444/
     * selectinput-in-a-class-in-eclipse-callback-not-found
     */
    
    import igeo.*;
    
    final Mesh mesh = new Mesh(this);
    
    void setup() {
      mesh.initialize().chooseFile();
    
      //IG.open("http://" + "igeo.jp/tutorial/code/igeo_tutorial1_2/"
      //+ "example_surf1.3dm");
    }
    

    Mesh.java:

    import igeo.*;
    import java.io.File;
    import processing.core.PApplet;
    
    public class Mesh {
      private final PApplet pa;
    
      public Mesh(PApplet p) {
        pa = p;
      }
    
      public Mesh initialize() {
        pa.size(800, 600, IG.GL);
    
        IG.clear();
        IG.perspective();
        IG.focus();
    
        return this;
      }
    
      public Mesh chooseFile() {
        // Assumes PApplet's reference. Won't find callback:
        //pa.selectInput("Select a mesh to process:", "fileSelected");
    
        // Specifies Mesh's reference. Callback is found:
        pa.selectInput("Select a mesh to process:", "fileSelected", null, this);
    
        return this;
      }
    
      public void fileSelected(File selection) {
        final String path;
    
        if (selection == null)
          pa.println("Window was closed or the user hit cancel.");
    
        else if (selection.isDirectory())
          pa.println("\"" + selection + "\" is a folder, not a file.");
    
        else if ((path = selection.getPath()).endsWith(".3dm")
          || path.endsWith(".obj")) {
          pa.println("User selected: " + path);
          IG.open(path);
        }
    
        else {
          pa.println(path + " is invalid!!!");
          pa.println("Gotta be '.3dm' or '.obj' extension file!");
        }
      }
    }
    

  • Thanks for putting so much effort in explaining, very much appreciated! I think I'm getting closer to understanding..

    Anyway, I applied it, and it works, thank you so much!

Sign In or Register to comment.