G4P multiple windows "function doesn't exist"/ help me understand

edited March 2016 in Library Questions

Hi! I'm trying to understand theG4P library example for multiple windows. It looks awesome, but I can't figure out where I am supposed to write functions in order to be able to use them in additional windows - at the moment if I try to write a function the usual way, I can call it inside the normal draw() but if I try to call it in one of the new windows, it says "function X does not exist".

I also don't really understand the MyWinData class in the example. I suspect this is related to why I can't get my functions to work with the new windows, but I'm in over my head a little bit, and have reached the limits of my understanding without outside help! Any advice or pointers to relevant examples will be appreciated. I've read the tutorial on the G4P website but I still don't really understand, and it doesn't specifically address functions. I'm not a programmer - sorry if I'm missing something obvious. Thanks in advance.

Tagged:

Answers

  • at the moment if I try to write a function the usual way, I can call it inside the normal draw() but if I try to call it in one of the new windows, it says "function X does not exist".

    Can you post a simple short example of what doesn't work so I can see where you are getting stuck?

    I also don't really understand the MyWinData class in the example.

    The first thing to note is that although the extra windows created with G4P look exactly the same as the Processing sketch window they are not. They are created from the main sketch code and can access any of the methods and global variables in the main sketch code. If you have multiple extra windows they all share the methods and global variables in the main sketch code.

    In most cases this is what you want but not always. For example the Mandelbrot example (comes with G4P) creates an interactive window for each view of the Mandelbrot set created. Now each of these windows share the same code for

    mouse interaction
    public void windowMouse(PApplet appc, GWinData data, MouseEvent event) {

    **and to draw the Mandelbrot **
    public void windowDraw(PApplet appc, GWinData data) {

    now if the windows also shared the same data they would all draw the same thing which defeats the purpose of the sketch.

    Using global variables in the main sketch code for each window is unrealistic because we don't know how many windows are going to be created in advance and how do the mouse and draw methods know which variable to use with which window.

    The solution is for each window to have its own data which is only accessible by that window. To do that G4P provides the GWinData class, notice that the mouse and draw method handlers accept a GWinData object data as a parameter.

    The GWinData class has just one field which references the GWindow that owns it. There are no other fields or methods because D4P doesn't know what the programmer intends to use this for. It is up to the programmer to create his/her own class that inherits from GWinData which the fields (variables) they need e.g.

    public class MyData extends GWinData { // inheritance
    
      public float x, y;
    
      public float distFrom(float px, py){
        return sqrt((px-x)*(px-x) + (py-y)*(py-y));
      }
    
    } // end of class
    

    In our mouse event handler we could get the distance from the mouse with

    public void windowMouse(PApplet appc, GWinData data, MouseEvent event) {
      MyWinData d = (MyWinData)data; // need to do this to acces our new method
      float dist = d.distFrom(appc.mouseX, appc.mouseY);
      // do something with dist
    }
    

    Using GWinData does require you to create your own classes but it is well worth the effort.

    HTH

  • Thanks so much for your reply, I have reproduced a simpler version of the error below. I am intending redEllipse() to be a global function which could be used in any window but I must be missing something. it works inside the main draw loop, but not in either of the new ones.

    I'm starting to wrap my head around classes for the data in each window, but not sure I'm quite there yet - will keep trying to understand it.

    import g4p_controls.*;
    
    GWindow[] window;
    
    public void setup() {
      size(100,100);
    
      window = new GWindow[2];
    
      //experimenter window
      window[0] = GWindow.getWindow(this, "Experimenter Window",100,100,400,800,JAVA2D);
      window[0].addData(new eData());
      window[0].addDrawHandler(this, "eDraw");
    
      //participant window
      window[1] = GWindow.getWindow(this, "Participant Window",600,100, 800,450,JAVA2D);
      window[1].addData(new pData());
      window[1].addDrawHandler(this, "pDraw");
    
    }
    //main draw
    public void draw() {
      redEllipse(50,50); //works as expected
    }
    
    //experimenter window
    public void eDraw(PApplet e, GWinData edat) {
     eData edata = (eData)edat;
     e.background(220);
     //expected behaviour: draw red ellipse with height and width (20,20)
     e.redEllipse(edata.ew,edata.eh); //error The function "redEllipse(int,int)" does not exist
    }
    
    
    //participant window
    public void pDraw(PApplet p, GWinData pdat) {
      pData pdata = (pData)pdat;
      p.background(255);
      //expected behaviour: draw red ellipse with height and width (30,30)
      p.redEllipse(pdata.pw,pdata.ph); //error: The function "redEllipse(int,int)" does not exist
    } 
    
    public void redEllipse(int redw,int redh) {
      fill(#FF0303);
      ellipse(50,50,redw,redh);
    }
    
    
    
    class eData extends GWinData {
      int ew = 20; //width
      int eh = 20; //height
    }
    
    class pData extends GWinData {
      int pw = 30; //width
      int ph = 30; //height
    }
    
  • Answer ✓

    The problem is caused because the PApplet class does not have a method called redEllipse. Adding the method to the sketch does not add it to the PApplet class.

    Secondly each GWindow has its own PApplet object.

    If you want a method / function to be shared by different windows and therefore different PApplet objects then include the PApplet object as a parameter like this

    synchronized public void redEllipse(PApplet app, int redw, int redh) {
      app.fill(#FF0303);
      app.ellipse(50,50,redw,redh);
    }
    

    Since each window will 'draw' itself in its own thread I have synchronized the method to avoid concurrent access errors. NOTE this may not be needed, try with and without. I am on my tablet at the moment so can't check myself.

    Since we have changed the method signature we also need to chan ge the call statements thus.

    Change line 23 to
    redEllipse(this, 50, 50);

    Change line 31 to
    redEllipse(e, edata.ew, edata.eh);

    Change line 40 to
    redEllipse(p, pdata.pw, pdata.ph);

  • edited March 2016

    Since each window will 'draw' itself in its own Thread I have synchronized the method to avoid concurrent access errors.

    As long as some PApplet "window" isn't trying to "draw" to another 1, synchronized is indeed unnecessary. :-B

  • Thankyou! I now have something which works, though it is slightly different to the answer - I will try this way later as well.

Sign In or Register to comment.