Adding a button event handler to a child window in G4P

I've noticed that none of the examples with G4P feature working buttons in external windows (created using the GWindow factory methods). I've also noticed GWindow has no addButtonHandler() to go along with addMouseHandler() and addDrawHandler(). What I want to know is, how do I get a GWindow object to handle button events without making my own implementation of GWindow? Surely there is some simpler way that I am missing? The same goes for slider events and other such things, since I'm sure I'm not the first one to want functioning UI widgets in an external toolbar window.

Answers

  • Answer ✓

    I suggest that you add the GUI Builder tool which provides a visual editor for creating GUIs with G4P. This allows you to easily create multiple windows and add other UI controls such as buttons and sliders to them.

    By examining the source code created with GUI Builder it will help you understand how G4P works.

    More information and video tutorials for using GUI Builder and G4P can be found on my website,

  • Thanks, I didn't realize you had built a scene builder tool. It's very useful, but it should probably be mentioned in the about page for G4P so nobody misses it.

    That said, I have decided that fewer windows is probably better.

  • I think I found the solution to this problem:

    To make a component such as GButton have an effect, you have to define it's handler method: public void handleButtonEvents(GButton button, GEvent event). In every example I've seen, the buttons, sliders, etc are declared in the main sketch. But what if the component is declared in a different PApplet (aka window)?

    The method button.getPApplet() returns the window that the button belongs to. With the button's window in hand, you can access the window's data attribute: button.getPApplet().data. By matching the button to the window, you can define the desired behavior and change that window's data.

    Here' an article on how to add data to your G4P windows by extending the GWinData class : http://www.lagers.org.uk/g4p/ex-windows/index.html

    This is my first time posting to a forum. I hope this helps someone ;)

  • @jorgeZapatero1 Thanks for your contribution you have documented a technique I hadn't considered or tried. There are a number of forum code examples showing how to create multiple windows in Processing and it maybe possible to use G4P with them using your technique. Since G4P supports multiple windows out of the box I would recommend using its GWindow control, not only is it designed to work with other G4P controls it is so much more powerful than any of the forum examples.

    This is a challenging topic so I will try to explain how G4P handles events and multiple windows.

    The very first release of G4P did not support multiple windows and had a simple mechanism for capturing control events. Consider the code below

    import g4p_controls.*;
    
    GButton btnDoSomething;
    
    void setup(){
      size(400,300);
      btnDoSomething = new GButton(this, 50, 20, 100, 20, "D Something");
    }
    
    void draw(){
      background(200,200,255);
    }
    

    If you run the program and click on the button nothing seems to happen. In truth the button generates an event but we don't have anything to capture it. What you will see is a very useful message in Processing's Console pane -

    You might want to add a method to handle GButton events syntax is
    public void handleButtonEvents(GButton button, GEvent event) { /* code */ }
    

    What happened is that when the button was created it looked for, but could not find, this method. Adding the event handler is so simple, simply copy and paste the second line into your program and add some code e.g.

    public void handleButtonEvents(GButton button, GEvent event) {
      if(button == btnDoSomething && event == GEvent.CLICKED){
        println("Button 'btnDoSomething' was clicked");
      }
    }
    

    The button now works and we can execute code when it is clicked.

    This technique works with all the controls and means you don't have to remember all the method names and parameters and it is still available in the latest version of G4P

    The event handler above is shared by all buttons so you need to check which button is clicked, hence the conditional statement inside.

    When there are lots of buttons the code inside the handler becomes unwieldy with multiple conditional statements. The solution is for every button to have its own event handler.

    In the following code I have done just that.

    import g4p_controls.*;
    
    GButton btnDoSomething;
    
    void setup() {
      size(400, 300);
      G4P.messagesEnabled(false);
      btnDoSomething = new GButton(this, 50, 20, 100, 20, "Do Something");
      btnDoSomething.addEventHandler(this, "doSomething");
    }
    
    void draw() {
      background(200, 200, 255);
    }
    
    public void doSomething(GButton source, GEvent event) {
      println("Button 'btnDoSomething' was clicked");
    }
    

    Notice that the generic event handler has been removed and we have specified our own handler instead. We no longer need the conditional statement because this event handler only belongs to one button. The statement in line 7 simply suppresses the messages about missing event handlers.

    What happens if the button is to appear in another window, lets see

    import g4p_controls.*;
    
    GButton btnDoSomething;
    GWindow myWindow;
    
    void setup() {
      size(400, 300);
      G4P.messagesEnabled(false);
      myWindow = GWindow.getWindow(this, "My Window", 60, 20, 200, 150, JAVA2D);
      myWindow.addDrawHandler(this, "myWindowDraw");
      btnDoSomething = new GButton(myWindow, 50, 20, 100, 20, "Do Something");
      btnDoSomething.addEventHandler(this, "doSomething");
    }
    
    void draw() {
      background(200, 200, 255);
    }
    
    public void myWindowDraw(PApplet app, GWinData data){
        app.background(255);
    }
    
    public void doSomething(GButton source, GEvent event) {
      println("Button 'btnDoSomething' was clicked");
    }
    

    We have modified the button creation code in line 11. If you compare them you see that the first parameter has changed to indicate that the button is to appear in myWindow not the main sketch window.

    The only other thing is the addition of the draw handler, myWindowDraw, for the second window. It performs the same actions as the draw method in the main sketch window.

    If you are using multiple windows then you should define your own event handlers for controls and do not rely on the default handlers such as handleButtonEvents

    I hope this makes things a little clearer.

Sign In or Register to comment.