Resizable window with constrained proportions

When I need the canvas to be resizable I use surface.setResizable(true);. However, I need to keep the width and height equal and can’t seem to find a way to apply constraints to do so.

I initially tried to manually set the size to keep the dimensions proportional, but that led to unpleasant flickering when I resized the window.

Any ideas on the best way to implement this are welcome.

1 Like

In FX2D mode:

public void setup() {

	stage = (Stage) ((Canvas) surface.getNative()).getScene().getWindow();

	stage.widthProperty().addListener(new ChangeListener<Number>() {
		public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
			stage.setHeight((double) newValue);

	stage.heightProperty().addListener(new ChangeListener<Number>() {
		public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
			stage.setWidth((double) newValue);

Unfortunately, I’m currently working in a P3D environment, so this solution isn’t what I currently need. I’m looking for a more universal solution, but it seems that wouldn’t be realistic.

Also, I’ve tested the code and gotten an error: Cannot refer to the non-final local variable stage defined in an enclosing scope from stage.setHeight((double) newValue);. Any idea on how to fix it?

Thanks for you quick reply!

I’m not certain, although it could be something to do with working in the Processing IDE, or lacking (some of) the following imports:

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.canvas.Canvas;
import javafx.stage.Stage;

We can always use keyword final in Java for almost anything. I use it all the time in my own sketches! :upside_down_face:

final Stage stage = (Stage) ((Canvas) surface.getNative()).getScene().getWindow();

1 Like

Thanks, that worked! I’ll try to look into P3D and see if I can get something working.

I’ve made a listener for P3D which works most of the time:

import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowUpdateEvent;

GLWindow window;

int pWidth;
int pHeight;

WindowListener windowListener = new WindowListener() {
  void windowDestroyed(WindowEvent e) {
  void windowDestroyNotify(WindowEvent e) {
  void windowGainedFocus(WindowEvent e) {
  void windowLostFocus(WindowEvent e) {
  void windowMoved(WindowEvent e) {
  void windowRepaint(WindowUpdateEvent e) {
  void windowResized(WindowEvent e) {
    int newSize = window.getWidth();
    if (window.getWidth() != pWidth) { 
      newSize = window.getWidth();
    if (window.getHeight() != pHeight) {
      newSize = window.getHeight();
    window.setSize(newSize, newSize);
    pWidth = window.getWidth();
    pHeight = window.getHeight();

void setup() {
  size(100, 100, P3D);
  pWidth = width;
  pHeight = height;
  window = (GLWindow) surface.getNative();

But since it still has some issues, I think I might just stick with surface.setSize(); for now.