G4P - Closing windows

edited October 2014 in Library Questions

Hello everyone!

I'm quite new at processing and I'm having an issue with closing windows and the G4P Tool. I've created a main window from where I want to choose a set of parameters to configure (checkbox). So far, I've managed to create the main window and the other windows for parameter configuration. This other set of windows is closing when I press the X button (Windows OS close). But I can't seem to keep that behavior going. If I try to repeat the close action, after opening and closing a first time, the window.setActionOnClose(window.CLOSE_WINDOW) doesn't work anymore. I was thinking that the best option would be to create the second window set only after making the selection on the main window but fiddling with the createGUI() function is not an option (every change on the GUI Builder will revert my changes) I've attached the files here: http://we.tl/ejQjB64Gmr

Can anyone help? Thanks!

Answers

  • edited March 2014 Answer ✓

    The problem with using the X button (Windows) to close the configuration windows is that G4P will attempt to release the resources allocated to the window, so if you attempt to re-use a closed wIndow the results will be unpredictable. This is true no matter how the window was closed.

    If you have a program with a window that you only want to use now-and-again, then leave the window close action as KEEP_OPEN and simply change the windows visibility. You can later use the forceClose() method when the window is no longer required, but once closed - DO NOT ATTEMPT TO USE IT AGAIN.

    but fiddling with the createGUI() function is not an option (every change on the GUI Builder will revert my changes)

    GUI Builder makes it quite clear in the gui.tab that the only safe place to place your own code is inside the event handlers.

    GUI Builder cannot be used to set every single option available in G4P, but it is safe to tweak GUI created, but only AFTER the call to createGUI()

    PS I have moved this the the 'Questions about Libraries' section

  • edited March 2014

    quark,

    Thank you! I'll work on trying to make my application resemble a configuration wizard and I may comeback to this topic to ask for help.

  • edited March 2014

    Any thoughts on how to display real-time collected data on a graph?

  • Can you point me to a way of opening the windows in the same frame

    Not sure what you mean by the same frame.

    GWindow is a sub class of java.awt.Frame so any methods for that class also apply to GWindows i.e.

    void setLocation(int x, int y);

    Point getLocation();

    If your sketch is executed as an application (i.e. run in Java mode) then it will open the main sketch window. In that case you can use the frame attribute to get the sketch window location.

    Try out the code below.

    // Need G4P library
    import g4p_controls.*;
    import java.awt.Point;
    
    public void setup() {
      size(320, 240, JAVA2D);
      createGUI();
      customGUI();
      // Place your setup code here
    
    }
    
    public void draw() {
      background(230);
      keepWindowTogether();
    }
    
    public void keepWindowTogether() {
      Point p = frame.getLocation();
      window.setLocation(p.x + 380, p.y + 20);
    }
    // Use this method to add additional statements
    // to customise the GUI controls
    public void customGUI() {
    }
    
    synchronized public void window_draw(GWinApplet appc, GWinData data) { //_CODE_:window:597837:
      appc.background(230);
    } //_CODE_:window:597837:
    
    
    
    // Create all the GUI controls. 
    // autogenerated do not edit
    public void createGUI(){
      G4P.messagesEnabled(false);
      G4P.setGlobalColorScheme(GCScheme.BLUE_SCHEME);
      G4P.setCursor(ARROW);
      if(frame != null)
        frame.setTitle("Sketch Window");
      window = new GWindow(this, "Config Window", 0, 0, 240, 120, false, JAVA2D);
      window.addDrawHandler(this, "window_draw");
    }
    
    // Variable declarations 
    // autogenerated do not edit
    GWindow window;
    
  • Please do not edit your posts once you get a reply.

    It can get very confusing for readers trying to follow the topic, also members' replies can appear to have no relevance to the questions because the questions have disappeared.

    ALWAYS add a new post to the topic unless you are correcting a simple typo.

    Any thoughts on how to display real-time collected data on a graph?

    You might look at the 'graphica' library.

  • quark,

    Thank you once again! My apologies for changing the post. Your help is much appreciated! I've downloaded the graphica library but I don't know how to integrate it with the G4P tool (I need to place a real-time graph somewhere on a G4P window). Should I use a sketchpad or floating panel object and then associate that with a function that creates the graph?

  • I don't know how to integrate it with the G4P tool

    You can't use graphica (or any other library) from inside the GUI Builder tool but most libraries work alongside the G4P library.

    Should I use a sketchpad or floating panel object and then associate that with a function that creates the graph?

    Forget that it won't work. Graphica was developed as an independent library and has to draw directly onto a PApplet surface.

    I need to place a real-time graph somewhere on a G4P window

    Every GWindow contains its own PApplet object, and this is what you use to draw inside the GWindow.

    I have modified the MultiplePlots example from graphics to include a GWindow (created with the GUI Builder tool). In the modified example the plots are drawn into the GWindow (variable name graphicaWindow). Apart from including G4P and creating the GWindow code the only changes are

    Each of the 4 plots were created with a statement like

    plot1 = new GPlot(this);

    where this is the main sketch PApplet object, is replaced with a statement like this

    plot1 = new GPlot(graphicaWindow.papplet);

    I also created a new method called drawPlots() and removed the plot drawing code from the draw() method and placed in in this new method. Finally I called the 'drawPlots()' from the draw handler for the GWindow graphicaWindow.

    You can download this example from here

  • Hello once again,

    quark, my apologies for not thanking you for your help. I did not resume my work until now for several reasons. So, thank you so much for your help. I'm here to ask for it again. To you or to anyone who can help. I'm trying to draw a plot on a window which is not the main. Code here. I can't seem to make the plot appear on the second window, even though the other two (on the main window) are working just fine. What I'm a doing wrong?

  • edited September 2014

    The problem is fixed you can download my solution sketch as an archived (zip) file here

    The main difference is that the call to plot.defaultDraw() is done from the appropriate draw() method.

  • Thank you for your help once more quark. The thing is that when I use serial port data, I get "Exception in event handles" warnings and I'm afraid that will get me to memory overflow errors (which I've had in the past, when trying to implent other solutions). Also, I don't want to draw the plots with the draw method (and hence the set framerate), just when I have new data available at the serial port. Each graph may need to be updated at a different time (and that's why I was thinking about using the serial port function to update the plots, not the draw methods).

  • Answer ✓

    There are two things here

    1) Update the plots (add / remove points)

    2) Draw the graph

    Now the draw() method should be responsible for (2) so keep my draw methods as is.

    The serial event handler should be responsible for (1) but not (2) so remove the three calls to plot.defaultDraw() from the serialEvent method.

    Let us know if it helps.

  • I see. That puts things in a new perspective (for me at least). But, unfortunately, that didn't solve the errors. They seem to be tied to the secondary window:

    ########## EXCEPTION IN EVENT HANDLER

    An error occured during execution of the eventhandler: CLASS: serie_pH METHOD: win_draw1

  • Answer ✓

    It took me a while but I have the solution.

    The problem is caused because win_draw1 is being called before the setup method is complete i.e. before plotpH is created. This might appear to be an impossibility but as soon as you realise that GWindow is effectively a secondary sketch executing in its own thread it is entirely possible.

    There are 2 possible solutions, this is the simpler one.

    synchronized public void win_draw1(GWinApplet appc, GWinData data) { //_CODE_:window1:793695:
      appc.background(230, 230, 200);
      if (plotpH != null)
        plotpH.defaultDraw();
    } //_CODE_:window1:793695:
    
  • quark,

    Thank you so much. It makes sense. I'm still learning the basics with processing, your help is very much appreciated. I've implemented your suggestion and everything works smoothly! Can you still present the other solution? I'm interested in learning about other possible solutions!

  • edited September 2014

    It's just my guess, but I think the most performant solution is stall the sketch in setup() via a loop until the other threads are completely initialized (non-null). O:-)

  • The other solution is also quite simple made slightly more difficult because you are using GUI Builder

    Start your sketch and launch GUI Builder (GB). In GB click on the second window and in the property grid delete the entry for the draw method name. When you go back to the PDE the code in GUI tab will have changed and the window draw method will have disappeared.

    NOW in the main sketch pde (not the gui tab)

    Put this as the last line in setup

    window1.addDrawHandler(this, "win_draw1");
    

    and add the method

    synchronized public void win_draw1(GWinApplet appc, GWinData data) { 
      appc.background(230, 230, 200);
      plotpH.defaultDraw();
    } 
    

    You will no longer need to test the value of plotpH because the plot is created BEFORE the draw handler is added to the window.

  • edited September 2014

    @quark, would synchronized still be needed after that? How many threads'd be invoking it after all? :-/

  • would synchronized still be needed after that?

    @GoToLoop Good question.

    Multiple windows first appeared in G4P in June 2009, can't remember if it was Processing 1.2.1 or 1.5.1 but it soon became apparent that in many situations there was flickering of the displays, particularly in the second window but sometimes also the main sketch display. The solution was using synchronized on the GWindow draw method.

    In the early alpha releases of Processing 2 the developers changed the event handling model of Processing dramatically and several libraries found themselves on the wrong side of the fence, G4P was one of them. I had to modify the library so I took the opportunity of a complete refactoring of G4P event system and in particular how GWindows were managed.

    I still think it might be needed since the method is being called from another thread and Processing does not provide much support or information about managing concurrent access violations.

    GUI Builder adds the synchronised keyword by default because it has no measurable affect on the frame rate and is the 'safe' option. It also saves me posting 'try adding synchronised' everytime someone gets a bit of flicker.

  • edited September 2014

    I still think it might be needed since the method is being called from another Thread...

    AFAIK, what determines whether a method (or a portion of it) should be synchronized is when more than 1 diff. Thread can potentially invoke it!

    A method declared as synchronized locks up on some particular this instance of its class.
    In this case, this is the sketch's reference and win_draw1() is a callback for some GWindow instance.

    As long as win_draw1() is registered to 1 GWindow instance only, synchronized is redundant.
    However, if more than 1 GWindow has that very same callback registered too, we gotta put synchronized back!
    As I understand it, each GWindow instance got its own Thread, is that so? <):)

  • As I understand it, each GWindow instance got its own Thread, is that so?

    Each GWindow is an instance of java.awt.Frame

    Each GWindow has a GWinApplet object embedded.

    GWinApplet extends PApplet so effectively each GWindow is a Processing sketch.

    Now the GWinApplet has the following methods -

    setup
    pre
    draw
    post
    mouseEvent
    keyEvent
    

    but they cannot be modified by the library user but we want each GWindow to be able to do 'display its own thing'.

    So each of these methods can invoke a method registered with GWindow hence

    window1.addDrawHandler(this, "win_draw1");

    This method is actually inside the main thread PApplet. It means that it can interfere / be affected by the main draw() method (when executed at the same time), also there is a risk of other concurrent access violations.

    I discovered that synchronized solved some difficult issues in the past and since it appears to have no noticeable effect on performance I am not worried if it is redundant.

    I suspect that you are right and that it may no longer be needed (G4P event and windows management system was completely overhauled with Process V2). Perhaps when I have time I will look into it more deeply but I have many other more challenging projects on the go to worry about it at the moment. :)

  • edited October 2014

    It means that it can interfere / be affected by the main draw() method (when executed at the same time), also there is a risk of other concurrent access violations.

    The main draw() is run by the sketch's "Animation Thread". And whether a programmer stupidly calls a reserved callback from draw() is another subject entirely!

    The matter is again how many unique threads are "supposed" to invoke some particular registered callback!
    In other words, is that callback "shared" by other threads? :>
    If the answer is not, then synchronized is redundant and just slows down the callback! :-&

  • edited October 2014

    ... and since it appears to have no noticeable effect on performance I am not worried if it is redundant.

    Although synchronized by itself has indeed very little performance impact, the lock/monitor/mutex chosen for it can make an app even slow to a crawl! :-S

    When a whole method is declared synchronized, its lock is implicitly this.
    Any other synchronized method belonging to that this instance automatically shares that lock!

    Let's say we've got 3 GWindow instances, and each 1 got its own synchronized callback method(s).
    B/c those methods share the same lock, when 1 callback is being run, the other GWindow instances gotta w8,
    even though they've got individual registered callbacks and don't share them! b-(
    It's obvious that synchronizing w/ a shared reference creates unnecessary contention and slowness! :-B

    But w8! It's gonna get worse now! After perusing the PApplet, I've found out some other synchronized methods there too!
    There aren't many, and actually most of them are circumstantial methods like redraw(), loop() & noLoop()!
    Unfortunately, there's a very nasty & important 1: protected synchronized void render() {}!
    Yup! The 1 responsible to render the canvas after draw()! [..]

    It means that when any other synchronized method is busy, the "Animation Thread" gotta w8 for it before entering render(), slowing down the main sketch!
    Likewise, once render() is being run, no other synchronized method locked on the sketch's this can run!

    I believe by now you understand how cheap synchronized methods are a bad lazy idea! 8-X
    If you really need to lock a method, you should use the synchronized block version w/ another unique reference!

    void win_draw1(GWinApplet appc, GWinData data) {
      synchronized (window1) {  // locking on object referenced by window1.
        appc.background(230, 230, 200);
        plotpH.defaultDraw();
      }
    }
    

    But only if you fear that win_draw1() is potentially being invoked by other GWindow threads! >-)

  • @GoToLoop Thanks for your research I will look at the options when I get a chance. It is possible for GWindows to share the same draw method, this is done in the Mandelbrot example where every generated window shares the same draw method but have their own appc and data objects.

  • @quark, @GoToLoop,

    Here I am again with another question. My interface is flowing nicely but now I need to plot a graph with two vertical axis, one at right and the other at left. Basically, points with one x and two y. I'm using the grafica library. My thought was to build two plots, each with the same x and two different sets of y values. I was thinking of drawing the plots on top of each other and enabling the right axis on one of them. Unfortunately, I've only been able to display the vertical line of the axis, not the values of it. I've looked into the GAxis and GPlot classes. Both mention the right axis but the GAxis seems to address its representation. I've noticed, tough, that the GAxis class refers to the PApplet itselft...I'm puzzled and can't seem to figure out the solution to my problem. Can you help?

  • @PetePT

    This question is very different from the topic title (G4P closing windows) and is in fact it is about using the graphica library. I suggest that you start a new topic for this and make sure you have the name of the library in the title.

    It is not surprising that GAxis refers to PApplet since a sketch is a PApplet object and gives access to all the drawing commands.

  • Hello, you can repair the link, I am working with multiple windows by G4P and graphica and that example would help me a lot, thank you very much.

    The problem is fixed you can download my solution sketch as an archived (zip) file here

    The main difference is that the call to plot.defaultDraw() is done from the appropriate draw() method.

  • That post is over a year old and I no longer have that file. Sorry :(

    Also G4P has been changed for Processing 3 and the latest version is not backwardly compatible. I am not sure whether graphica works with PS2 but its API has changed since I first used it.

Sign In or Register to comment.