How do I change the size of the display window?

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:

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: