G4P How to use fireallevents?

Hi Peter, I’m trying to use the “RELEASED” event for an image button, and I’m referring to your reference page, under GImageButton, mouseEvent:

void handleButtonEvents(void handleButtonEvents(GImageButton button, GEvent event) {
   if(button == btnName && event == GEvent.CLICKED){
       // code for button click event
   }

Is this called automatically somehow, or do I need to put this in draw() or setup()?

I tried adding btnName.fireAllEvents(true); in setup, and just adding the handleButtonEvents outside of draw and setup, but nothing happens yet.

Thanks for any clarification.

By the way, typo I think - that’s a direct copy, and void handleButtonEvents is twice.

Thanks!

Mike

In the very first release of G4P the PRESSED and RELEASED events were fired by default. Then I discovered this was not normal behaviour in other GUIs and it was forcing users to check the event type in all mouse event handlers to detect a click.

My first reaction was to remove the offending code but since I hate removing working code I gave the users a choice with the firsAllEvents(...) method.

When fire all events is enabled
Events fired are

  • PRESSED when the mouse button is pressed over the button

when the mouse button is released we get a choice of events

  • CLICKED if the mouse has not moved since the PRESSED event
  • RELEASED if the mouse has not moved since the PRESSED event
import g4p_controls.*;

public void setup() {
  size(320, 370, JAVA2D);
  createGUI();
}

public void draw() {
  background(200, 200, 230);
}

public void processButtonEvents(GButton source, GEvent event) {
  txaOutput.appendText("Button event: " +  event + " @ " + millis());
}

public void setAllEvents(GCheckbox source, GEvent event) {
  btnFireEvent.fireAllEvents(source.isSelected());
  txaOutput.appendText("++++++++++++++++++++++++++++++++++");
}

public void createGUI() {
  G4P.messagesEnabled(false);
  G4P.setDisplayFont("Arial", G4P.PLAIN, 14);
  surface.setTitle("Fire All Events Test Sketch");
  btnFireEvent = new GButton(this, 20, 10, 120, 30);
  btnFireEvent.setText("Click Me !");
  btnFireEvent.addEventHandler(this, "processButtonEvents");
  cbxAllEvents = new GCheckbox(this, 150, 10, 150, 30);
  cbxAllEvents.setIconAlign(GAlign.LEFT, GAlign.MIDDLE);
  cbxAllEvents.setText("Fire All Events?");
  cbxAllEvents.setOpaque(true);
  cbxAllEvents.addEventHandler(this, "setAllEvents");
  txaOutput = new GTextArea(this, 20, 50, 280, 300, G4P.SCROLLBARS_VERTICAL_ONLY | G4P.SCROLLBARS_AUTOHIDE);
  txaOutput.setOpaque(true);
}

GButton btnFireEvent;
GCheckbox cbxAllEvents;
GTextArea txaOutput;

Note:
The OS is responsible for detecting mouse events and firing suitable events to the active application which is in our case Processing which makes them available to the sketch so we must work within this framework.

Thank you so much for explaining this Peter, and for the excellent example! It works great!

I noted the “RELEASED” event does not fire…any reason for this? Your documentation shows released is available.

I’ve found so far that release events are best for detecting, for example, double clicks - the click events are a bit unreliable.

Also, any way to use only release event, as opposed to all events firing? I have a reliable double click working, but since the button also fires its own click, I can’t use it (button fires the click, and my double click detects a double click, but the single click is already fired - and I’m also using the single click on the same button to make the GUI more streamlined).

Worst case, I can roll my own buttons here - I’ve done it before, not too bad, but I really like using your controls.

Thank you again, I so appreciate your time!

Mike

Thanks this is going to be added as a library example. But then you say

I explained the circumstances which cause a GEvent.RELEASED event being fired :roll_eyes: so I don’t undersatnd this statement. What circumstances are you expecting the RELEASED event?

When you choose to fire-all-events then you need to check the event types and perform the appropriate action. This replaces the function in the example but tests for event type

public void processButtonEvents(GButton source, GEvent event) {
  switch(event) {
  case CLICKED:
    txaOutput.appendText("Button event:   GEvent.CLICKED   @ " + millis());
    break;
  case PRESSED:
    txaOutput.appendText("Button event:   GEvent.PRESSED   @ " + millis());
    break;
  case RELEASED:
    txaOutput.appendText("Button event:   GEvent.RELEASED  @ " + millis());
    break;
  }
}
2 Likes

Thank you for explaining, and for the great example. I really appreciate it.

In your sample, when you run it, the released event does not show in the list. So I was confused. I still don’t get it. How to get the released to show, in the sample code?

Screenshot 2024-05-16 at 6.08.11 AM

Sorry to be dense. Programming is a second language for me :slight_smile:

Also, where to put this? Does it matter?

public void processButtonEvents(GButton source, GEvent event) {
etc...

Thanks kindly.

Mike

It is either or NOT both

No you can put this anywhere unless created by GUI Builder, but it must pair up with

btnFireEvent.addEventHandler(this, "processButtonEvents");
2 Likes

Thank you so much Peter.

Last Q for now - is there a way to get mouseover on your controls, besides usual method with processing? I don’t see any mouseover events in buttons.

Thank you so much for your amazing support.

Mike

No - sorry about that.

1 Like

No worries. Thanks Peter.

By the way, I’m using the GUI Builder whenever I can (it’s great ta!), and I am wondering if I can’t use the Release event since the button is made by the GUI Builder?

Well I decided to do it all in code, removing those buttons in question from the GUI Builder.

Buttons look fine, but do not respond to the events.

As globals, I added these:

GImageButton imgBtnPrev; 
GImageButton imgBtnNext; 

My code in setup is this:

imgBtnPrev = new GImageButton(this, 240, 563, 25, 25, new String[] { "prevUp.png", "prevOver.png", "prevPressed.png" } );
  imgBtnPrev.addEventHandler(this, "handleButtonEvents");
  imgBtnNext = new GImageButton(this, 558, 563, 25, 25, new String[] { "nextUp.png", "nextOver.png", "nextPressed.png" } );
  imgBtnNext.addEventHandler(this, "handleButtonEvents");
  
  imgBtnPrev.fireAllEvents(true);
  imgBtnNext.fireAllEvents(true); 
  btnFireEvent.addEventHandler(this, "handleButtonEvents");

That last line, which you said I needed to add, says:

“The name “btnFireEvent” cannot be recognized”

And I also have as a void after draw:

void handleButtonEvents(GImageButton button, GEvent event) {
   if(button == imgBtnPrev && event == GEvent.RELEASED){
     println("FIRRRRED!");
     if (!doubleClick) movePrev();
     else {
      doubleClick = false;
      moveFirst();
    }
   }
   if(button == imgBtnNext && event == GEvent.RELEASED){
     if (!doubleClick) moveNext();
     else {
       doubleClick = false;
       moveLast();
     }
   }
}//end void

doubleClick and singleClick work well, in separate code, using a combo of detecting mouse releases and counting clicks. They fire correctly.

But nothing happens with the buttons other than they respond to mouseovers and appear to change when clicked.

Sorry if this is so basic; I’m trying to make these buttons do two things - one thing when single clicked, another when double clicked.

If it’s too complex or whatever, I dont’ want to take up your valuable time. But if there’s an easy fix which I’m missing, I’d love to hear it.

Thanks again Peter.

Mike

The answer is yes because you put a switch statement inside the event handler and test for event type - see my handler-with-switch example earlier. That was created using GUI Builder :smile:

2 Likes

I can’t think of any GUI where the buttons respond directly with double-clicks. I could be wrong but I don’t think so.

1 Like

I understand. I’m trying to keep the GUI simpler and not add 2 more buttons to move to end or beginning if poss. More like an easter egg but nice added functionality. For me, I’m all about simplicity and minimalism when I can. Two buttons instead of four.

I’m not clear about this line:

btnFireEvent.addEventHandler(this, "handleButtonEvents");

It won’t recognize it and shows it as an error. Obvs it’s not right; how do I modify it to work correctly? As I said, the buttons do nothing as of right now - the event handler is not working at all. Even though it “should” be working…even it won’t show the println test statement, so it’s not hooked up correctly, regardless of single/double clicking.

By the way it all works fine if I just use your GUI builder and a single click; the voids movePrev() and moveNext() work fine…

Thank you again Peter.

Mike

So more testing, it doesn’t recognize the RELEASED event at all. If I change

if(button == imgBtnPrev && event == RELEASED){

to

if(button == imgBtnPrev && event == GEvent.CLICKED){

then the event handler works (but not for released, just for click).

Clearly it isn’t recognizing the RELEASED event, even though there’s no error message when I use it.

So sorry to keep asking you Peter, but am I missing something obvious?

All the best,
Mike

In G4P there are two techniques for handling events, they are ‘by control type’ and ‘by control’

  1. By Control Type

This was the original technique that was used in the first release and is still remains available. In this technique when the sketch creates a button e.g. btn = new GButton(this, ...); G4P will look for a method called handleButtonEvents that has two parameters a GButton reference and a GEvent reference if it can’t find this method then it will display a message in the console tab -

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

BTW this method is called an event handler.

This is great because it shows the correct method signature and the user can always copy and paste the second line into the source code. I always found this useful because I couldn’t remember the method signatures :innocent:

So if we had a sketch with 5 buttons this event handler will process all events fired by them. this requires a series of if statements inside the method to decide which button was firing the event. By default buttons only fire events of type GEvent.CLICKED so it is not necessary to test the event type.

If a button executes the method fireAllEvents(true); then that button can fire three types of event
GEvent.CLICKED, GEvent.PRESSED and GEvent.RELEASED

so it would be necessary to differentiate the event type using if or switch statements.

When a button is clicked it fires two events GEvent.PRESSED followed by GEvent.CLICKED and each one would result in the event handler being executed separately i.e. the event handler is called twice

Other control types have different event handlers e.g.

// Text fields and ares
public void handleTextEvents(GEditableTextControl textcontrol, GEvent event) { /* code */ }
// Sliders and custom sliders
public void handleSliderEvents(GValueControl slider, GEvent event) { /* code */ }

These control types already fire multiple event types.
#---------------------------------------------------------------------------------------------------#

  1. By Individual Control

This was introduced later when GUI Builder became available. Now each control can have its own event handler so in the statement
btnFireEvent.addEventHandler(this, "processButtonEvents");

there is a GButton called btnFireEvent and the event handler signature will be
public void processButtonEvents(GButton source, GEvent event) { }

NOTE:
In a previous post you had
btnFireEvent.addEventHandler(this, "handleButtonEvents");

the sketch did not recognize bthFireEvents because no such button has been created. Also I recommend that you do not use method names used by technique 1, it will lead to inconsistent behaviour.

Having a unique event handler for each control is the much preferred technique because it simplifies the code in each event handler.

#---------------------------------------------------------------------------------------------------#

Both techniques are still available and can be used in the same sketch that is why it is important that event handlers for technique 2 have different names to the default names used in technique 1.

Last point for the moment - the syntax foe testing the event type is slightly different between if and switch statements e.g.

if(button == imgBtnPrev && event == GEvent.RELEASED){
  ...
}
// Need the 'GEvent.'

versus

 switch(event) {
  case CLICKED:
    txaOutput.appendText("Button event:   GEvent.CLICKED   @ " + millis());
    break;
  case PRESSED:
    txaOutput.appendText("Button event:   GEvent.PRESSED   @ " + millis());
    break;
  case RELEASED:
    txaOutput.appendText("Button event:   GEvent.RELEASED  @ " + millis());
    break;
  }
  // 'Gevent.' not required
3 Likes

Peter…do you have a donate a button?

I’ll need to donate a kidney…

thank you SO MUCH for all of your time to so clearly explain everything!

Truly, humbly, THANK YOU!!!

I will work my way through your explanation, and I so appreciate all the immense genius, talent, and time this has taken you :smiling_face_with_three_hearts:

So I’ve taken onboard what you said. For some reason, despite best efforts, still the RELEASED is not seen or fired.

Globals:

GImageButton imgBtnPrev; 
GImageButton imgBtnNext; 

in setup (not showing all of setup, but relevant):

createGUI();
customGUI();
  
  imgBtnPrev = new GImageButton(this, 240, 563, 25, 25, new String[] { "prevUp.png", "prevOver.png", "prevPressed.png" } );
  imgBtnPrev.fireAllEvents(true);
  imgBtnPrev.addEventHandler(this, "handleImgBtnPrevEvents");
  imgBtnNext = new GImageButton(this, 558, 563, 25, 25, new String[] { "nextUp.png", "nextOver.png", "nextPressed.png" } );
  imgBtnNext.fireAllEvents(true); 
  imgBtnNext.addEventHandler(this, "handleImgBtnNextEvents");  
  

And the handlers:

void handleImgBtnPrevEvents(GEvent event) {
     if (event == GEvent.RELEASED){
       println("IMGBTN PREV FIRED!");
       if (!doubleClick) movePrev();
     else {
      doubleClick = false;
      moveFirst();
    }
   }
}//end void

void handleImgBtnNextEvents(GEvent event) {
   if(event == GEvent.RELEASED){
     println("IMGBTN NEXT FIRED!");
     if (!doubleClick) moveNext();
     else {
      doubleClick = false;
      moveLast();
    }
   }
}//end void

Note I did try the full switch case statement for one of the button event handlers:

void handleImgBtnPrevEvents(GEvent event) {
  switch(event) {
  case CLICKED:
    println("clicked...............");
    //txaOutput.appendText("Button event:   GEvent.CLICKED   @ " + millis());
    break;
  case PRESSED:
    println("pressed...............");
    //txaOutput.appendText("Button event:   GEvent.PRESSED   @ " + millis());
    break;
  case RELEASED:
    println("released...............");
    //txaOutput.appendText("Button event:   GEvent.RELEASED  @ " + millis());
    break;
  default:
    break;
  }
}//end void

But this did not even fire with the click.

I’m not sure what I’m missing here now…thought I followed all your suggestions to a T.

I may just give in and use a separate button as you suggested earlier, but I hate defeat!

This requires an event handler

void handleImgBtnPrevEvents(GImageButton source, GEvent event){
  ...
}

In your code you are missing the first parameter :exploding_head: :grinning:

2 Likes