How do I change the size of the display window?

Not sure, maybe on the canvas frame. see line 489 here.

The difference between setSize() and surface.setSize()

The following discussion applies to Processing sketches using Java mode only.

There are two parts to the sketch

  1. The window - this is a java.awt.JFrame which as the name suggest is a simple window frame with a title bar and close icon which can hold content. This is referenced by the variable surface
  2. The canvas - this is the drawing surface and its starting size is fixed with the size(w, h) statement found in the setup() or settings() method. It is an object of type java.awt.Canvas

When a processing sketch is executed it creates the canvas using the values from size(w, h) and a JFrame whose size is just big enough to surround the canvas.

Now in Java awt/Swing you can change the size of either the window or the canvas without changing the size of the other component. In Processing this is not the case, if you modify the frame size with surface.setSize() then the canvas is resized but not the the other way round,

Now back to the final problem - although setSize() does not change the window size it does change the variables width and height

So in this sketch you would expect the green rectangle to fill the display it doesn’t. I suspect that this is a side-effect caused by software updates and although not desirable behaviour is easily avoided.

void setup() {
  size(600, 600);
  surface.setResizable(true);
  setSize(500, 400); // Does not resize window
}

void draw() {
  background(255, 200, 0);
  fill(0, 192, 0);
  // expect this next line to fill display with green rectangle
  rect(0, 0, width, height);
  // but it doesn't
}
4 Likes

Okay, so I’ve done some further experimentation, and yeah…it’s not just my code that’s flopping up here.

void setup() {
  size(300,400);
  surface.setResizable(true);
}

void draw() {
  background(0);
  surface.setSize(300,400);
}

If I run this sketch, the code will make a perpetual effort to keep the size at 300,400, no matter how much I resize things. Unfortunately, this effort appears to be in vain. Observe:

Keep in mind, I did nothing special here. I simply clicked and dragged to expand the window. Every time I do this, the moment I release the mouse button, it fails to rescale back to 300,400.

I should also note that, when I tried having it println the dimensions, it was still convinced the width and height was 300,400. So that’s great…

(It’s also worth noting that my end goal is to create a program that I can resize, but who’s width to height ratio is always constant.)

I tried your code and when I used the mouse to resize the window it always went back to 300x400 whenever I stopped dragging or released the mouse button. (I was running it on a iMac)

I do suggest you modify the program to avoid changing the window size while its trying to render the frame. Try this

int w, h;

void setup() {
  size(300, 400);
  w = width;
  h = height;
  surface.setResizable(true);
  registerMethod("pre", this);
}

void pre() {
  if (w != width || h != height) {
    surface.setSize(w, h);
  }
}

void draw() {
  background(255, 200, 0);
  fill(0, 200, 0);
  rect(0.25 * width, 0.25 * height, 0.5* width, 0.5 * height);
}

No luck :disappointed:

I should note, I’m doing this on Windows 10.

Also worth noting, when I change the window size with my mouse, the window bugs out graphically until I stop resizing it. This happens regardless of if I call the setSize() function.

Perhaps someone else can try in o Windows 10 and see if they get the same result.

I could send a video if you want?

Okay, so as it turns out, what was tripping me up was the “snap windows” feature in Windows 10.

Once I disabled this feature, the program worked exactly as you said it would. Granted, it still had those graphical glitches I described, but still.

I assume you mean that the windows ‘flickers’ If that is the case then try this code - on my machine gave good results unless you resized the window quickly.

int w, h;

void setup() {
  size(300, 400);
  w = width;
  h = height;
  surface.setResizable(true);
}

void mouseEntered() {
  if (w != width || h != height) {
    surface.setSize(w, h);
  }
}

void mouseExited() {
  if (w != width || h != height) {
    surface.setSize(w, h);
  }
}

void draw() {
  background(255, 200, 0);
  fill(0, 200, 0);
  rect(0.25 * width, 0.25 * height, 0.5* width, 0.5 * height);
}

The above code is not perfect - sometimes the window does not resize after releasing the mouse but that is fixable but requires more sophisticated code.

Maintaining the aspect ratio is significantly harder to do well. I might have a go at producing a more complete example this afternoon. Watch this space.

1 Like

Cool! I didn’t know there was a mouseEntered or mouseExited function.

By any chance, is there any way the console can figure out if the mouse is being held down when it’s outside the PApplet console?

Neither I. I wonder why the request on taking it into the reference was denied.
It seems really useful.

1 Like

Plain Java seems not capable of doing this. You can find some tricks using overlays etc, but the correct way I think to do this is using JNA Here is also a Java lib.
Personally, I use AHK for Windows objects and dll access by launching it, as an in the background running app.

I have been doing some experiments to avoid the visual glitches without success. The problem appears that the window size is altered before Java events are generated so we are always correcting the window size.

There may be a way to do it in pure Java by overriding the JFrame class but this will not work in Processing because it takes charge of creating the JFrame so we couldn’t use a child class.

@noel I have no idea why it was not included in the web reference, you will have to ask Reas, but generally you don’t get detailed explanations when an issue is rejected and closed.

1 Like

I took a whack at it myself, and yeah…this is pretty hard to do. I took the code you gave me, and added a modification that makes it so the window is resized, not only when the mouse enters or exits the window, but also if it’s been at least a certain amount of frames since the user attempted to change the window size. The problem with this modification is, after the time activated resizing, if the mouse button is still being held down, the user can still resize the window, which would result in an instantaneous change in window size.

I think if someone really, really, really wanted to, they could possibly fix the glitches with the java robots, but at that point it’s just overkill.

I have been doing some further research and this is what I believe to be happening.

When the user resizes a window with the mouse.

  1. The OS detects the mouse event
  2. The OS processes the mouse event to
    – activate / deactivate applications
    – mimimise / maximise / resize any windows affected
  3. The OS passes the mouse event onto the active application for further action which depends on application

If this is true then window is resized before processing is informed that the size has changed so the visual glitches are inevitable unless the mouse event can be caught at the OS level.

Of course this could be complete rubbish :wink:

Well, in that case, I suppose I’ll just have to make a fork on your code, where the dimensions update every time you leave and exit the canvas, and that should probably be the best we can do. I’ve already implemented the “maintain aspect ratio” part. Now I just have to make it so the position updates properly as well, and add in a special case involving the minimum and maximum window size. I’ll be sure to post the code when I’m done! Thanks so much for the help so far!

P.S. is there any possibility that I could detect the position of the mouse outside the canvas if I were to make another canvas (a class derived from PApplet), made it the size of the screen, setVisible(false), and record its mouseX, mouseY, and mousePressed values? Or are those values only recorded when the window is selected?

You can invoke method PSurface::getNative() in order to access its underlying window object:
http://Processing.GitHub.io/processing-javadocs/core/processing/core/PSurface.html#getNative--

The class CanvasResizeWatcher does that in its constructor:

  public CanvasResizeWatcher(final PApplet pa, boolean now) {
    window = ( p = pa ).getSurface().getNative();
    pg = pa.getGraphics();
    immediate = now;
  }
1 Like

Two things. First of all, @GoToLoop, where can I download the “gotoloop.listener.CanvasResizeWatcher” library? I see the GitHub page for it all, but I don’t know how to download that as a library. I’m very curious to see what it does, and how it could help me with this predicament.

Second of all, I finished that fork I promised. The code is attached below. Whenever your mouse goes into/out of the canvas, the size is updated so that aspect ratio is preserved.

//Credit goes to Processing forum user Quark for the original code this was based off.
//https://discourse.processing.org/u/quark

float ratio=4.0/3; //record the height over width ratio

int widthLast=300, heightLast=400; //these record the dimensions every time the mouse enters/exits the canvas
int xLast, yLast;                  //these record the position of the top left of the canvas right before we resize the window
int xLFrame, yLFrame;              //these record the position of the top left of the canvas in the previous frame

void settings() {
  size(300,400); //for this example, we will go for a size of 300,400, correlating to a 3:4 aspect ratio
}

//A note to novice programmers reading this, you could just as well put size() in the setup function, so long as your dimensions are expressed as literals

void setup() {
  surface.setResizable(true); //make the canvas resizable
  
  xLFrame=xLast=get_sketch_location_x(); //initialize these values
  yLFrame=yLast=get_sketch_location_y();
}

void draw() {
  scale(width/300.0, height/400.0); //scale the canvas appropriately
  
  background(255, 200, 0); //This is what quark originally had in the draw function. I modified it, though,
  fill(0, 200, 0);         //so you could write code without having to constantly reference the width &
  rect(75,100,150,200);    //height (assuming you wanted to draw more than just a rectangle).  Of course, this
                           //has its drawbacks, especially if you plan on having consistent strokeWeight.
  
  
  int x=get_sketch_location_x(), y=get_sketch_location_y(); //compute the canvas's position
  
  if(x==xLFrame && y==yLFrame && widthLast==width && heightLast==height) { //if the position didn't change between frames, and the width & height aren't being changed
    xLast=x; yLast=y;                                                      //record xLast & yLast
  }
  
  xLFrame=x; yLFrame=y; //set these values to the canvas's position at the end of the frame
}

void mouseEntered() {
  updateDimensions(); //change dimensions every time the mouse enters the canvas
}

void mouseExited() {
  updateDimensions(); //and every time it leaves the canvas
}

void updateDimensions() { //this code is run in the mouseEntered & mouseExited functions. It's the least buggy way I can maintain aspect ratio.
  
  if(width!=widthLast || height!=heightLast) { //Check that the dimensions are different than they were last time this function ran
    
    int x=get_sketch_location_x(), y=get_sketch_location_y(); //canvas's position
    
    int minW=surface.MIN_WINDOW_WIDTH,
        minH=surface.MIN_WINDOW_HEIGHT; //minimum window dimensions
    float prefW, prefH;                 //preferred window dimensions
    
    /////////////////////////COMPUTE PREFERRED DIMENSIONS////////////////////////////////////
    
    if(width!=widthLast && height!=heightLast) { //if the user resized the window diagonally:
      prefW=(width+height*ratio)/(sq(ratio)+1); prefH=prefW*ratio; //option 1: choose dimensions that minimize Pythagorean distance
      //prefH=0.5*(width*ratio+height); prefW=prefH/ratio;         //option 2: same as option 1, but stretched & skewed
      //prefW=width; prefH=width*ratio;                            //option 3: preserve the width. This is how a lot of desktop card games maintain aspect ratio
      //prefW=height/ratio; prefW=height;                          //option 4: same as option 3, but w/ the height
    }                                          //go with whatever option you like best.
    else if(width!=widthLast) { prefW=width; prefH=width*ratio;   } //user only changed the width
    else                      { prefW=height/ratio; prefH=height; } //user only changed the height
    
    /////////////////////////////////////SET DIMENSIONS/////////////////////////////////////////
    
    if(prefW >=minW && prefH >=minH) { surface.setSize(round(prefW),round(prefH)); } //preferred dimensions aren't too small
    
    else {                                                                           //preferred dimensions are too small:
      if(minW*ratio >= minH) { surface.setSize(minW, round(minW*ratio)); } //choose smallest possible dimensions that preserve aspect ratio
      else                   { surface.setSize(round(minW/ratio), minH); } //this means either width = minW or height = minH
    }
    
    ///////////////////////////////////SET LOCATION///////////////////////////////////
    
    //here, we change the location so the corner/edge opposite to the one the mouse dragged stays put
    
    int xPos=x, yPos=y;   //xPos, yPos: where we want the canvas to be (init to current position)
    if(x != xLast) { xPos=xLast+widthLast-width;   } //x changed since resizing: edge/corner is on the left
    if(y != yLast) { yPos=yLast+heightLast-height; } //y changed since resizing: edge/corner is on the top
    
    if(x!=xPos || y!=yPos) { surface.setLocation(xPos,yPos); } //set location
    
    
    /////////////////////////////////UPDATE////////////////////////////
    
    widthLast=width; heightLast=height; //record the most recent values for the width and height
  }
  
}

///////////////////////////POSITION FETCHING FUNCTIONS I DON'T UNDERSTAND EVEN SLIGHTLY/////////////////////////////////////////////////

//Credit goes to Processing forum user "Stanlepunk" for the following code.
//profile:        https://discourse.processing.org/u/stanlepunk/
//original post:  https://discourse.processing.org/t/getlocation-of-the-sketch/5763
//He also lists an "improved" version of the code, compatible with all renderers (e.g. P2D, P3D).  I couldn't get it to work.  The function "get_renderer()" seems not to exist.

int get_sketch_location_x() {
  return getJFrame(getSurface()).getX();
}

int get_sketch_location_y() {
  return getJFrame(getSurface()).getY();
}

 
static final javax.swing.JFrame getJFrame(final PSurface surface) {
  return (javax.swing.JFrame) ( (processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
}

There are a couple bugs/exploits, and I might work to fix them some day…but it’d probably be like putting lipstick on a pig, if we’re being honest.

Known Bugs:

  • Not compatible with P2D or P3D renderers.
  • If you try resizing the window to be bigger than MAX_WINDOW_SIZE, things kinda just break. This should be easy to fix, but for some reason, I actually can’t seem to figure out the maximum window size.
  • If you resize the window to the minimum size, the window will sometimes move a pixel away from where it was before. This bug persists anytime you setResizable(true), regardless of if you use my code. Thus, there’s no real way for me to fix it.
  • While resizing the window, visual glitches occur frequently. Again, this happens regardless of if you use my code. It’s just a problem with either Processing or Windows OS.
  • If you resize the window, then (without putting your mouse back in the canvas first) you move the window, then finally put your mouse back in the canvas, the window will move back to where it was before step 1. This is technically more of an exploit than a glitch, as the code is just looking at whatever corner/edge is opposite to the one you were dragging around, then places that corner/edge in the same location it was at the start. I thought this’d be easy to fix, but it’s actually kinda tricky, so I more or less gave up.
  • The file “CanvasResizeWatcher.java” is itself the library.
  • Just create a new file tab on the Processing IDE (PDE) w/ that exactly name w/o forgetting its “.java” extension.
  • Then copy & paste the contents of that file from the Gist repo onto the new “.java” tab.
  • Use import gotoloop.listener.CanvasResizeWatcher; in order to use its main top class.
  • Basically it automatically calls back our own frameResized() every time the sketch’s window changes its dimensions.
  • The file “Canvas_Resize_Watcher.pde” has an example on how to define our own frameResized() callback.

As stated already the library “CanvasResizeWatcher.java” got code on how to apply the window object returned by PSurface::getNative() for each of the 4 Processing renderers (JAVA2D, FX2D, P2D, P3D).

So, first of all, congrats on making a library, especially one that can read input this deep from the computer. I could never do something like that.

Second of all…I’ll be honest, part of the reason it’s taken me so long to respond to this is I’m too dumb to figure out how to do anything useful with this. I’m afraid I have nothing meaningful to contribute. :frowning_face: