Problem using GPanel and child windows in G4P library

This is a further refinement to the sketch I posted in my previous question. I want to divide the main window into panels, and from some of the panels, I want to open a child window. The code below works fine without panels, but if I add panels to the main window (see comments in code below), then the objects in the child window don’t work. For example, the droplist in the child window works if I don’t have panels in the main window, but seems to be disabled if I have panels in the main window. I added a call to ‘setEnabled()’ but it doesn’t seem to help. Once again, there’s probably something I’m missing, but I don’t know what. I looked through the examples provided, but couldn’t find any example that opens a child window from a panel.

This is the working version of the sketch (without panels). But if you uncomment the indicated lines, the droplist no longer works.

import g4p_controls.*;

GPanel panel = null;
GButton button = null;
GWindow window;
GDropList dropList;
String[] dest = {"Selection 1","Selection 2","Selection 3"};
int selected = 0;

public void setup() {
  size(600,400,JAVA2D);
  G4P.setCtrlMode(GControlMode.CORNER);
  G4P.setGlobalColorScheme(GCScheme.GREEN_SCHEME);
  G4P.setMouseOverEnabled(true);
  //panel = new GPanel(this,0,0,200,200,"PANEL 1"); // Uncomment this line
  //panel.setCollapsed(false);                      // Uncomment this line
  //panel.setCollapsible(false);                    // Uncomment this line
  //panel.setDraggable(false);                      // Uncomment this line
  //panel.setOpaque(true);                          // Uncomment this line
  button = new GButton(this, 15, 40, 60, 20);
  button.setText("SETUP");
  button.addEventHandler(this,"buttonHandler");
  //panel.addControl(button);                       // Uncomment this line
}
public void draw() {
  background(179,237,179);
}
public void buttonHandler (GButton source, GEvent event) {
  makeChildWindow();
  button.setEnabled(false);
}
public void makeChildWindow () {
  window = GWindow.getWindow(this,"Child Window",20,40,400,200,JAVA2D);
  window.setActionOnClose(G4P.CLOSE_WINDOW);
  window.addDrawHandler(this,"windowDraw");
  window.addOnCloseHandler(this,"windowClose");
  dropList = new GDropList(window, 20, 20, 120, 100, 5);
  dropList.addEventHandler(this, "dropListHandler");
  dropList.setItems(dest,selected);
  dropList.setEnabled(true);
}
public void windowDraw(PApplet app, GWinData data) {
  app.background(179,237,179);
}
public void windowClose(GWindow window) {
  button.setEnabled(true);
}
public void dropListHandler (GDropList source, GEvent event) {
  println("selected text = "+source.getSelectedText());
  selected = source.getSelectedIndex();
  dropList.setItems(dest,selected);
}

If you’re wondering where I’m going with all this, I want to develop a graphical front-end for an audio application written in Pure Data (see http://puredata.info/). Attached is a screen print of a non-functional mock-up of the final product.

EffectsRack|654x499

1 Like

I have been doing some testing. I have moved the panel to the right with

//panel = new GPanel(this,300,0,200,200,"PANEL 1"); // Uncomment this line

so that I could build the panel step by step and finally add the button. So it seems that as you suspected adding the button to the panel appears to disable the droplist. This is probably a bug in G4P so it might take awhile to find a solution.

rest assured I will be looking into the problem.

BTW you do not need to add this line in the droplist handler, after all G4P has already done this for you.

dropList.setItems(dest,selected);

2 Likes

Thanks. BTW, I’m having the same problem with option groups, text boxes, etc. Probably any kind of object except labels. They all seem to be disabled if the child window is opened from a panel.

That was the first thing I checked and discovered. Puzzling since the control still reacts when the mouse is over it but does not respond to clicks.

BTW I should have mentioned it before but I do don’t recommend closing secondary windows and then recreate them when they are needed again. Instead I would normally create the windows I need at setup and then make them visible/invisible on demand.

Processing was never designed to use multi-window applications so libraries like G4P and controlP5 are stretching the envelope to provide them You can read more about this on my website.

I thought of doing that, but I wasn’t sure if it was still necessary. Closing and re-opening them seems to be working fine, although maybe there’s more overhead in closing and re-opening them. Do you think it would make any difference, as far as this issue is concerned? If you think it might solve the problem, I’ll certainly go ahead and try it.

It will not solve your problem but it might be safer especially if you are to export the application to other platforms.

I have just had a revelation and I am 99.9999% confident I know what is causing the problem. The solution will take some time to make sure I don’t introduce other bugs.

In the meantime I have looked at your mock-up very impressive but do you need to use GPanel’s if you are not going to allow them to move or collapse?

It isn’t really necessary, I guess, but I wanted to use them to add a title to each panel indicating the function, it looks nicer than a label. Also, it helps to organize the code a little better, I think.

Personally I can’t see how it can improve source code organisation.

Is that because of the opaque background behind the buttons etc.? A simple rect(...) will do that for you.

Anyway I will try and fix the issue as soon as I can.

Yeah, I’m just being lazy, I guess.

I have found a simple solution to the problem it only involved changing two lines of code :relieved: but I need more testing to check it works properly. If everything is OK I will issue a new release tomorrow and let you know here.

1 Like

I was looking for examples of sketches that create child windows, and when running the Mandelbrot example, I got an error on the following line (line 126 of G4P_Mandelbrot.pde):

G4P.showMessage(this, "Selection box size must be at least 1x1 pixel.", "Invalid Selection Box", G4P.WARNING);

I fixed it by changing “G4P.WARNING” to “G4P.WARN_MESSAGE”.
You might want to include this in the next release.

P.S. The documentation still refers to the old names, G4P.PLAIN, G4P.ERROR, G4P.INFO, G4P.WARNING, G4P.QUERY, under “showMessage”.

Thanks for letting me know, it is so difficult keeping such a large project consistent in all areas. I have made the appropriate changes for version 4.3.4 which will be released within the next couple of hours. :smile:

G4P 4.3.4 is now available for download and manual installation from Sourceforge. Alternatively it can be installed using the Contributions Manager but it usually takes at least 24hours before Processing checks for updates.

1 Like

Thanks, it works fine now.

I tried making the child window invisible instead of closing it, but it doesn’t seem to work. Probably something I’m doing wrong, though. I looked through the examples but couldn’t find any that use the technique. I’ll play with it a bit more before posting any code, though. I think I’ve already taken up too much of your time.

This is my attempt to use setVisible() for the child window instead of opening and closing it. The child window opens, but I can’t close it (unless I press [ESC], which closes both windows). If I click on the close icon in the top right corner of the child window, nothing happens. I think the problem is that I’m calling ‘setActionOnClose(G4P.KEEP_OPEN)’ when I create the child window. To fix it, do I have to add a “close” button to the child window? Or is there some other way? I was hoping to avoid adding a “close” button.

import g4p_controls.*;

GButton button = null;
GWindow window;

public void setup() {
  size(600,400,JAVA2D);
  G4P.setGlobalColorScheme(GCScheme.GREEN_SCHEME);
  button = new GButton(this, 15, 40, 60, 20);
  button.setText("SETUP");
  button.addEventHandler(this,"buttonHandler");
}
public void draw() {
  background(179,237,179);
}
public void buttonHandler (GButton source, GEvent event) {
  window = GWindow.getWindow(this,"Child Window",20,40,400,200,JAVA2D);
  window.setVisible(false);
  window.setActionOnClose(G4P.KEEP_OPEN);
  window.addDrawHandler(this,"windowDraw");
  window.addOnCloseHandler(this,"windowClose");
  window.addDrawHandler(this,"windowDraw");
  window.setVisible(true);
  button.setEnabled(false);
}
public void drawController(PApplet app, GWinData data) {
  app.background(179,237,179);
  window.draw();
}
public void windowDraw(PApplet app, GWinData data) {
  app.background(179,237,179);
}
public void windowClose(GWindow window) {
  button.setEnabled(true);
  window.setVisible(false);
}
1 Like

OK a few things here.

  1. To avoid closing <> recreate window cycles we need to create the new window(s) in setup and then hide them. We can simulate opening and closing the window by controlling its visibility.
  2. We must prevent the window from being closed otherwise we might try and change the visibility of a non-existent window and crash. Hence the G4P.KEEP_OPEN option.
  3. Since we don’t actually close the window then we don’t need a close handlers because they will never be called :smile:

Remember the whole point of controlling the visibility is to avoid having to open/close window cycles

So here is my version.

import g4p_controls.*;

GButton btnHide, btnShow;
GWindow window;

public void setup() {
  size(600, 400, JAVA2D);
  G4P.setGlobalColorScheme(GCScheme.GREEN_SCHEME);
  btnShow = new GButton(this, 15, 40, 60, 20);
  btnShow.setText("SETUP");
  btnShow.addEventHandler(this, "windowVisibility");
  createOtherWindow();
}

public void createOtherWindow() {
  window = GWindow.getWindow(this, "Child Window", 20, 40, 400, 200, JAVA2D);
  window.setVisible(false);
  window.setActionOnClose(G4P.KEEP_OPEN);
  window.addDrawHandler(this, "windowDraw");
  window.setVisible(false);
  btnHide = new GButton(window, window.width - 55, window.height - 30, 50, 25, "Hide");
  btnHide.addEventHandler(this, "windowVisibility");
}

public void draw() {
  background(179, 237, 179);
}

public void windowVisibility (GButton source, GEvent event) {
  if (source == btnShow) {
    showHideWindow(true);
  } else if (source == btnHide) {
    showHideWindow(false);
  }
}

public void showHideWindow(boolean show) {
  if (show) {
    window.setVisible(true);
    btnShow.setEnabled(false);
  } else {
    window.setVisible(false);
    btnShow.setEnabled(true);
  }
}

public void windowDraw(PApplet app, GWinData data) {
  app.background(179, 237, 179);
}
1 Like

So basically, I do need to add a button to hide the window? I was hoping to avoid that. The other thing is that when I first start the application, the child window appears very briefly before it’s hidden. That would be OK if I just had one child window, but I plan on having 5 or 6 of them, for different purposes. To have all of them flicker even very briefly at start-up is a little distracting. Could this just be a Windows issue? I haven’t tried it under Linux yet (although I will), and I don’t have access to a Mac, so I can’t test it.

I understand your point about avoiding the need to open and close windows, but it happens very quickly, at least on my computer, so I’m not concerned about the overhead, as long as it’s stable. And it seems to be stable so far.

That’s the big question and you have to decide based on your computer and OS.

There is a third option :smile: that is a hybrid. Just one button on the main form, on first click it creates the second window after that it toggles the window’s visibility. This sketch demonstrates what I mean.

import g4p_controls.*;

GButton btnHide, btnWindow;
GWindow window = null;

public void setup() {
  size(600, 400, JAVA2D);
  G4P.setGlobalColorScheme(GCScheme.GREEN_SCHEME);
  btnWindow = new GButton(this, 15, 40, 60, 20);
  btnWindow.setText("Show");
  btnWindow.addEventHandler(this, "windowHandler");
}

public void createOtherWindow() {
  window = GWindow.getWindow(this, "Child Window", 20, 40, 400, 200, JAVA2D);
  window.setVisible(false);
  window.setActionOnClose(G4P.KEEP_OPEN);
  window.addDrawHandler(this, "windowDraw");
  window.setVisible(true);
}

public void draw() {
  background(179, 237, 179);
}

public void windowHandler(GButton source, GEvent event) {
  if (window == null) { 
    // if the window hasn't been created then do so
    createOtherWindow();
    btnWindow.setText("Hide");
  } else {
    // the window exists so toggle its visibility
    if (window.isVisible()) {
      window.setVisible(false);
      btnWindow.setText("Show");
    } else {
      window.setVisible(true);
      btnWindow.setText("Hide");
    }
  }
}

public void windowDraw(PApplet app, GWinData data) {
  app.background(179, 237, 179);
}
1 Like

If I have to have an exit button, I think it makes more sense to have it in the child window. So I modified your third option a bit. But I think it’s liable to confuse some people if the close icon in the top right corner doesn’t do anything. Whether you’re a Windows user, a Mac user or a Linux user, this is standard behaviour, isn’t it?

import g4p_controls.*;

GButton btnWindow;
GButton btnExit;
GWindow window = null;

public void setup() {
  size(600, 400, JAVA2D);
  G4P.setGlobalColorScheme(GCScheme.GREEN_SCHEME);
  btnWindow = new GButton(this, 15, 40, 60, 20);
  btnWindow.setText("Show");
  btnWindow.addEventHandler(this, "showHandler");
}
public void createOtherWindow() {
  window = GWindow.getWindow(this, "Child Window", 20, 40, 400, 200, JAVA2D);
  window.setVisible(false);
  window.setActionOnClose(G4P.KEEP_OPEN);
  window.addDrawHandler(this, "windowDraw");
  window.setVisible(true);
  btnExit = new GButton(window, 15, 40, 60, 20);
  btnExit.setText("Exit");
  btnExit.addEventHandler(this, "exitHandler");
}
public void draw() {
  background(179, 237, 179);
}
public void showHandler(GButton source, GEvent event) {
  if (window == null) { 
    // if the window hasn't been created then do so
    createOtherWindow();
  } else {
    // toggle visibility
    window.setVisible(!(window.isVisible()));
  }
  btnWindow.setEnabled(false);
}
public void exitHandler(GButton source, GEvent event) {
  window.setVisible(false);
  btnWindow.setEnabled(true);
}
public void windowDraw(PApplet app, GWinData data) {
  app.background(179, 237, 179);
}