G4P - Secondary Window Buttons Not Always Reliable

Hi, I’m using the fantastic G4P library, and I’ve made some secondary windows with buttons on them.

I’m using the technique of creating them null, and then showing/hiding them with other buttons.

I’m finding that sometimes you have to click the buttons 2-3 times in the secondary window before they register a click. I’m wondering if there’s something I can do to make them work 100% reliably?

Here’s code from one of the sample windows that exhibits this behavior:

public void optionsDraw(PApplet app, GWinData data){
    app.background(127);
    //app.image(optionsIcon, 123, 10);   
    app.stroke(100);
    app.strokeWeight(2);
    app.fill(127);
    app.rect(15, 70, 270, 70, 5);
  }
  
void createOptionsWindow() {
  int windowWidth = 300;
  int windowHeight = 200;
  options =  GWindow.getWindow(this, "Options", width/2 + 120, height/2 + 70, windowWidth, windowHeight, JAVA2D);
  options.setActionOnClose(G4P.HIDE_WINDOW);
  options.addDrawHandler(this, "optionsDraw");
  options.addMouseHandler(this, "optionsMouse");
  options.addKeyHandler(this, "optionsKey");
  //options.addData(new MyData());
  cbShowToolTips = new GCheckbox(options, 22, 80, 120, 20, "Show Tooltips");
  cbShowToolTips.setLocalColorScheme(GCScheme.SCHEME_15);
  cbShowToolTips.setSelected(blnShowToolTip);
  cbShowToolTips.addEventHandler(this, "cbShowToolTips_clicked");
  
  btnCancelOptions = new GButton (options, windowWidth/2 - buttonWidth - 15, windowHeight - buttonYOffset, buttonWidth, buttonHeight, "Cancel");
  btnCancelOptions.addEventHandler(this, "btnCancelOptions_clicked");
  btnCancelOptions.setLocalColorScheme(GCScheme.SCHEME_9);
  
  btnOKOptions = new GButton (options, windowWidth/2 + 15, windowHeight - buttonYOffset, buttonWidth, buttonHeight, "OK");
  btnOKOptions.addEventHandler(this, "btnOKOptions_clicked");
  btnOKOptions.setLocalColorScheme(GCScheme.SCHEME_9);
}
  
public void optionsMouse(PApplet app, GWinData data, MouseEvent event) {
    // Saves doing it for every variable in MyData class
    //MyData myData = (MyData) data;
    //if(event.getAction() == MouseEvent.CLICK){
    //  myData.lastClickX = mouseX;
    //  myData.lastClickY = mouseY;
    //}
}

public void optionsKey(PApplet app, GWinData data, KeyEvent event) {
  if (event.getKey() == RETURN || event.getKey() == ENTER) options.setVisible(false);
}

public class MyData extends GWinData {
    // The variables can be anything you like.
    public int lastClickX,lastClickY;
}

public void cbShowToolTips_clicked(GCheckbox source, GEvent event) {
  if (cbShowToolTips.isSelected()) blnShowToolTip = true;
  else blnShowToolTip = false;
  showHideToolTips();  
}

void showHideToolTips() { 
    
  if (blnShowToolTip) toolTipGap = 0;
  else toolTipGap = 1000; 
  setTooltips();  
}

public void btnCancelOptions_clicked(GButton source, GEvent event) {
  println("CANCEL CLICKED!");
  if (options != null) options.setVisible(false);  
}

public void btnOKOptions_clicked(GButton source, GEvent event) {
  println("OK CLICKED!");
  try{
    optString[1] = str(blnShowToolTip);
    saveStrings("options.txt", optString);
  }
  catch(Exception e) {
    e.printStackTrace();
  }
  if (options != null) options.setVisible(false);  
}

It works most of the time fine, but every once in awhile, you have to click either OK or Cancel 2-3 times before it registers the click.

It’s puzzling…

Thanks for any insights anyone may have,

Mike

Why are you coding your app this way?

Just use Swing.

Thank you. I appreciate the links and the suggestion.

In many places I have read that Processing doesn’t play well with the Swing library, so that’s why.

I’m heavily invested now in the G4P library so I probably wouldn’t change, unless I just can’t accomplish what I need to.

But the button clicking unreliability is problematic.

I have dabbled a little with Swing and Java.

I have read that Processing doesn’t play well with the Swing library

That’s not a problem if you use a separate thread. It was discussed here:https://discourse.processing.org/t/swing-components-in-default-processingwindow/35483

A few things have been learned since that original post. For example the default canvas can be used for conventional drawing calls using draw() if you reduce the size of it and use it like a normal control instead of removing it entirely (obviates use of JPanel for drawing). Swing components can also be used in Python with py5. I’m mentioning all of this not to persuade you to switch from G4P but to clear up the threading issue; Processing plays nicely with Swing if you use a separate thread. We’ve also been using it in py5 without the additional thread and so far no problems that we are aware of.

2 Likes

That’s really useful @svan !

Thank you!

I tried to reproduce the problem (see sketch code below) without experiencing any problems. Why don’t you try it. :smile:

The most likely causes for a sluggish GUI is

  • time consuming code during frame-rendering-method or event-handling-methods or
  • setting the frame-rate too low.
import g4p_controls.*;

public void setup() {
  size(480, 240, JAVA2D);
  createGUI();
}

public void draw() {
  background(160, 255, 160);
}

public void btn1_click(GButton source, GEvent event) { //_CODE_:btn1:726568:
  lbl1.setText("btn1 - clicked @ " + millis());
} //_CODE_:btn1:726568:

synchronized public void wnd1_draw(PApplet appc, GWinData data) { //_CODE_:wnd1:980755:
  appc.background(255, 180, 180);
} //_CODE_:wnd1:980755:

public void btn2_click(GButton source, GEvent event) { //_CODE_:btn2:317161:
  lbl2.setText("btn2 - clicked @ " + millis());
} //_CODE_:btn2:317161:

public void createGUI() {
  G4P.messagesEnabled(false);
  G4P.setGlobalColorScheme(GCScheme.BLUE_SCHEME);
  G4P.setMouseOverEnabled(false);
  surface.setTitle("Main Window");
  btn1 = new GButton(this, 30, 20, 230, 30);
  btn1.setText("Button on Main Window");
  btn1.setLocalColorScheme(GCScheme.GREEN_SCHEME);
  btn1.addEventHandler(this, "btn1_click");
  lbl1 = new GLabel(this, 30, 70, 220, 30);
  lbl1.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
  lbl1.setText("My label");
  lbl1.setLocalColorScheme(GCScheme.GREEN_SCHEME);
  lbl1.setOpaque(true);
  wnd1 = GWindow.getWindow(this, "Secondary Window", 200, 100, 260, 120, JAVA2D);
  wnd1.noLoop();
  wnd1.setActionOnClose(G4P.KEEP_OPEN);
  wnd1.addDrawHandler(this, "wnd1_draw");
  btn2 = new GButton(wnd1, 10, 10, 240, 30);
  btn2.setText("Button on Secondary WIndow");
  btn2.setLocalColorScheme(GCScheme.RED_SCHEME);
  btn2.addEventHandler(this, "btn2_click");
  lbl2 = new GLabel(wnd1, 10, 60, 240, 30);
  lbl2.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
  lbl2.setText("?");
  lbl2.setLocalColorScheme(GCScheme.RED_SCHEME);
  lbl2.setOpaque(true);
  wnd1.loop();
}

GButton btn1;
GLabel lbl1;
GWindow wnd1;
GButton btn2;
GLabel lbl2;

2 Likes

Thank you so much Peter! You always take care in your responses. Gratitude.

Yes I tried your lovely example and it works perfectly.

In my code, it’s not that the buttons are sluggish to respond - they 25% of the time simply do not respond at all. In fact I’ve had the button change color when you click on it, and it does not trigger the click event. Like, WTAF? How could it register the mouseover and state change of the button but not trigger the click event?

I had a similar kind of problem before when I was making my own buttons - the click event was not reliable, and in another post someone suggested using the mouse release method instead, and in that case it solved the problem. I could perhaps try to get your buttons to respond to the release events using our previous discussion on fireAllEvents…

In the main window, and subwindows, I don’t have some crazy rendering code going on either, so I doubt it’s taxing the processor. It’s a very simple little box and the main window isn’t crazy processor intensive; just some buttons and text fields. And I have not changed the frame rate.

I have noticed that your image button controls do not exhibit this behavior so far; I may try making the OK and Cancel buttons into images and try them that way and see if that resolves it. That would also have the additional advantage that I can make a default button a different color, if it resolves the issues.

It’s one of those intermittent issues that’s hard to troubleshoot because it happens occasionally, but not consistently. It could work 10x in a row perfectly and then fail the next time. Enough to make me question my sanity.

I will keep working with it - and many thanks for your consistently kind and supportive responses. I seriously owe you a pint!

Thank you so much,

Mike

Here’s a little video showing the issue:

Video

Thanks for watching

Mike

PS I am using this code in the draw() method:

 if(frameCount <  2) return; // first two frames are blank but does not stop G4P
  

to ensure all items load simultaneously between your library and other GUI elements (you gave this to me in another post).

Could this be part of the issue?

EDIT: Nevermind; disabled it and it’s not changing behavior.

Thanks,

Mike

Working backwards -

I assume that the frameCount code is only included in the main window draw method in which case it should make no difference at all. Of course you can test this yourself by commenting out the line :innocent:

I had a look at your video and I see what you mean I will have to think about it.

In Java the rendering method (in the case of Processing the draw function) and event handler code (mouse clicks etc) are ALL executed on the main event handling thread. It is not unknown for users to put in some processor intensive code inside these methods (or other methods called by them) e.g.

  • calculating a ‘Game of Life’ iteration with 12million cells
  • calculating a hires Mandelbrot image
  • loading large amounts of data from a hard drive
  • synchronous http requests

At 60fps there is ~17ms to execute all events queued on the main event thread. Since our computers are multitasking and there are lots of other tasks being processed then really we need to limit any processing to <10ms.

I doubt whether your application is doing anything like that so it should not be an issue.

3 Likes

I’m grateful for any thoughts you may have.

Yes I did REM out the line and it had no effect. Still same issue.

I wonder if using another “thread” would help…haven’t delved into those yet though.

Thanks for any insights, and I hope you are doing well kind sir.

Mike

In G4P each window is effectively a separate Processing applet, so each window has its own event thread.

3 Likes

Thank you Peter for explaining.

Just curious if you had any further thoughts on the button clicking reliability?

Thx,

Mike

So far in testing using image buttons instead of the standard buttons, I can confirm that the unreliable behavior is gone. Clicking an image button appears to work 100% of the time; no missed clicks or funny business.

I will update this post again after more testing, but this seems to have done the trick.

Suggesting there is “something” going on with the standard buttons that the image buttons do not suffer from…

In any case I’m thrilled to have reliable clicks happening now, but of course it’s a bit more work to create all the images for the image buttons. But worth it.

Thanks,

Mike

I will do some experiments to see if I can find the problem and produce a solution. I make no promises since I have not been able to reproduce the problem yet.

2 Likes

Peter, I certainly do not expect you to spend a single second on this - honestly.

I have it working 100% reliably with image buttons. It could be something in my code, which is too byzantine to share or decipher.

So please, don’t spend any time on it. If something like it ever comes up again, well, then just know the image buttons are always responding to click events 100% in separate Windows.

Thank you, and apologies; I do not mean to give you assignments or stress.

Mike

PS - it worked out even better because now I’ve colored the default buttons so it’s even more intuitive. Plus I have the whole messaging system working perfectly now with individual icons for each kind of message.

Although I am unable to recreate this problem I have compared the mouse handling source code in GButton and GImageButton and believe I have a solution, even though I can’t test it.

2 Likes

If you share it I can test it on an older version of the app I’m making.

Your support and caring are waaaay out of line kind sir! Seriously can I buy you a pint or send you a thank-you ££?? Send me a PM with a link.

I don’t take you for granted.

All the best and THANK YOU!

Mike

Thanks to @Thundercat for testing my solution and confirming it worked.

This issue has been resolved and will appear in the next release 4.3.11

2 Likes