Creating detached windows

Hi!
I found some code by others here, who helped me to create processing applications that don’t have a default windows title bar. This inspired me to try this, I just don’t know on how to start.

Now, I want to know, if it is possible to create a processing window with P2D, that allows having the main Processing window & multiple other windows, that are positioned relative to the main processing window, which also use processing and not swing.
The windows would also need to have an order, in which they are displayed.

This could result in something like this:

This would allow for a 3d environment, with 2d menus or other cool things. I’m thinking about an office software where the user can drag toolboxes around.

Also you could use multiple Processing instances or sketches, but then the taskbar would be full of multiple windows.

Thanks for any advice -Libby

1 Like

Hi, Why did you delete your comment? Not trying to be weird.
-Libby

I thought that the default window for Processing was a JFrame (which is a Swing component), but apparently it is an AWT Frame component that some code casts to a JFrame. I’m working on your question and can make three windows, but I’m not able to move them around the way I want. I found out you don’t have to use a Mouse Handler for the canvas; you can also use mouseX and mouseY but the result is not good enough to post so far.

Oh, that explains it. Thank you for working on my question, that’s really kind of you. :slight_smile:
-Libby

Apparently, the library g4p can also create multiple windows

1 Like

Looks like you’re happy with G4P so I’m not going to post the code for this. It uses two PApplet windows in additon to the default window and is a little complicated.

1 Like

impressive.

besides, you can also in one window combine 3D and 2D elements (when this is your main interest). Sometimes named HUD: Head-up display - Wikipedia

see #9: 25 life-saving tips for Processing | Amnon P5 - Experiments with Processing by Amnon Owed

  • so you could make two frames / boxes (2D) inside the 3D window
1 Like

Hi! Thank you for this, but im not that good with coding, so would you be able to give the code for it?
-Libby

That is also a great way! Thanks you for your help.
-Libby

1 Like

Reference for undecorated window: https://kodejava.org/how-do-i-create-undecorated-frame/

The following source code creates two PApplet windows (undecorated) in addition to the default window.
Addendum: Edited to condense to single class. Developed on Mac; however, should run on all three operating systems.

//https://kodejava.org/how-do-i-create-undecorated-frame/

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

Window wnd1;
Window wnd2;

class Window extends PApplet {
  Frame frame;
  Canvas canvas;

  Point offset = new Point();

  int x, y, w, h;
  color bkgrnd;
  
  public Window(int x, int y, int w, int h, color bkgrnd) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.bkgrnd = bkgrnd;
    
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
    frame = ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
    canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative();
    
    frame.removeNotify();
    frame.setUndecorated(true);
    frame.addNotify();
    frame.setLocation(x, y);
   
    canvas.addMouseListener(new MouseAdapter() {
      void mousePressed(MouseEvent msEvnt) {
        offset.x = msEvnt.getX();
        offset.y = msEvnt.getY();
      }
    }
    );

    canvas.addMouseMotionListener(new MouseMotionAdapter() {
      void mouseDragged(MouseEvent msEvnt) {
        Point pt = frame.getLocation();
        frame.setLocation(pt.x + msEvnt.getX() - offset.x, pt.y + msEvnt.getY() - offset.y);
      }
    }
    );
  }

  void myBtnDisplay() {
    fill(255, 226, 13); // button color
    strokeWeight(4.0);
    stroke(255);
    rect( 160, 30, 100, 30, 15); // rounded rect
    fill(0); // text color
    textSize(20.0);
    textAlign(CENTER, CENTER);
    text("myBtn", 160, 30-4, 100, 30);
  }

  void settings() {
    size(w, h);  // Sets size of canvas
  }

  void setup() {
    background(bkgrnd);
    frame.setResizable(true); // To avoid strip at bottom
  }

  void draw() {
    fill(0, 255, 255);
    circle(50, 50, 50);
    fill(0, 255, 0);
    rect(100, 100, 100, 30);
    myBtnDisplay();
    fill(0, 255, 0);
    textSize(20.0);
    text("hello", 50, 150, 100, 44);
  }

  void mousePressed() {
    if ((mouseX >= 160) && (mouseX <= 160 + 100) && (mouseY >= 30) && (mouseY <= 30 + 30)) {
      println("You hit the button.");
    }
  }
}

// ========= Default Window ========== //

void setup() {
  size(400, 400);
  surface.setTitle("Default Window");
  wnd1 = new Window(100,100,400,400,color(255,255,0));
  wnd2 = new Window(720,100,300,500,color(0,0,255));
}

void draw(){
  fill(255, 0, 0);
  circle(width/2, height/2, 200);
}
2 Likes

Wow! I’m impressed! Thanky you so much for that code! :slight_smile:
-Libby

Hi!
i get an Error, i don’t know if im missing a library or it is like this only on Linux, or im too stupid, but i can’t get anything out from this error :fearful:

java.lang.IllegalStateException: Component must have a valid peer
	at java.desktop/java.awt.Component$FlipBufferStrategy.flip(Component.java:4179)
	at java.desktop/java.awt.Component$FlipBufferStrategy.show(Component.java:4306)
	at processing.awt.PSurfaceAWT.render(PSurfaceAWT.java:250)
	at processing.awt.PSurfaceAWT$9.callDraw(PSurfaceAWT.java:1387)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:356)
IllegalStateException: Component must have a valid peer

-Libby

It’s a harmless error. Make sure that you’re on the main window when you hit ‘run’; not on one of the tabs.

Hi! When I hit run it will give out one of these errors, but sometimes it runs, it doesn’t change when i’m on the main tab/window.

With a very small chance (i would say 5%) the windows open with 0 errors!

Error variant 1

java.lang.IllegalStateException: Component must have a valid peer
at java.desktop/java.awt.Component$FlipBufferStrategy.getBackBuffer(Component.java:4154)
at java.desktop/java.awt.Component$FlipBufferStrategy.updateInternalBuffers(Component.java:4137)
at java.desktop/java.awt.Component$FlipBufferStrategy.createBuffers(Component.java:4128)
at java.desktop/java.awt.Component$FlipBufferStrategy.(Component.java:4069)
at java.desktop/java.awt.Component$FlipSubRegionBufferStrategy.(Component.java:4601)
at java.desktop/java.awt.Component.createBufferStrategy(Component.java:3932)
at java.desktop/java.awt.Canvas.createBufferStrategy(Canvas.java:201)
at java.desktop/java.awt.Component.createBufferStrategy(Component.java:3856)
at java.desktop/java.awt.Canvas.createBufferStrategy(Canvas.java:176)
at processing.awt.PSurfaceAWT.render(PSurfaceAWT.java:234)
at processing.awt.PSurfaceAWT$9.callDraw(PSurfaceAWT.java:1387)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:356)
IllegalStateException: Component must have a valid peer

Error variant 2

java.lang.IllegalStateException: Component must have a valid peer
at java.desktop/java.awt.Component$FlipBufferStrategy.getBackBuffer(Component.java:4154)
at java.desktop/java.awt.Component$FlipBufferStrategy.updateInternalBuffers(Component.java:4137)
at java.desktop/java.awt.Component$FlipBufferStrategy.revalidate(Component.java:4258)
at java.desktop/java.awt.Component$FlipBufferStrategy.getDrawGraphics(Component.java:4235)
at processing.awt.PSurfaceAWT.render(PSurfaceAWT.java:243)
at processing.awt.PSurfaceAWT$9.callDraw(PSurfaceAWT.java:1387)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:356)
IllegalStateException: Component must have a valid peer

Error variant 3

java.lang.NullPointerException: Cannot invoke “java.awt.Image.getGraphics()” because “this.drawBuffer” is null
at java.desktop/java.awt.Component$FlipBufferStrategy.getDrawGraphics(Component.java:4236)
at processing.awt.PSurfaceAWT.render(PSurfaceAWT.java:243)
at processing.awt.PSurfaceAWT$9.callDraw(PSurfaceAWT.java:1387)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:356)
NullPointerException

Could it possible be because of my java version?

Version Info (java --version) gave this out:

openjdk 18.0.2-ea 2022-07-19 OpenJDK Runtime Environment (build 18.0.2-ea+9-Ubuntu-222.04) OpenJDK 64-Bit Server VM (build 18.0.2-ea+9-Ubuntu-222.04, mixed mode, sharing)

Its pretty weird, i don’t know why this happens, i’m sorry for the inconvienience! </3
-Libby

I’ve rarely seen that error on MacOS also, but its usually because I was trying to ‘run’ from one of the tabs. I don’t know why it happens more on Linux and really don’t understand why it happens at all. I do have a Linux box and will try to run it on that system when I get a chance. I’m using a little later version of OpenJDK than you, but I don’t know if that makes any difference.

1 Like

I’m very disappointed by the way the demo performs on Linux operating system; as far as I’m concerned it is unusable (for reasons unclear to me). It is acceptable on MacOS, although it occasionally throws the same error message as the one you have documented. I have no idea why it is so bad on Linux and will also try to test it on Windows. If it performs poorly there as well I will take down the post. Thanks for making me aware of this problem; it is not what I intended.

1 Like

Hi! I think the problem is on processings side tho… :frowning:
-Libby

You may be right. There are other ways of getting multiple windows with JFrames or JavaFx which I avoided because you indicated you didn’t want to use Swing components, but that may be a better way to go. The undecorated window appears to have some issues also.

1 Like

Are you able to run this demo on your Linux operating system:

//http://www.java2s.com/example/java/swing/managing-window-types.html

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

class Utility extends JFrame {
  int x, y, w, h;

  public Utility(int x, int y, int w, int h) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.setTitle("Utility Window");
    this.setBounds(x, y, w, h);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setType(Type.UTILITY);
    this.setLayout(new FlowLayout());
    JButton exitButton = new JButton("Quit");
    this.add(exitButton);
    exitButton.addActionListener(event->System.exit(0));
  }
}

void setup() {
  size(400, 400);
  surface.setTitle("Default Processing Window");
  SwingUtilities.invokeLater(() -> {
    Utility wnd1 = new Utility(100, 100, 400, 300);
    wnd1.setVisible(true);
    Utility wnd2 = new Utility(400, 100, 300, 200);
    wnd2.setVisible(true);
  }
  );
}

1 Like

Hi! Thats also really cool, since you can pass variables through swing windows, could it be possible to pass 2 pgraphics objects through it?
-Libby