0

How do I get the resolution of the screen application (during resize) but only once the mouse has been released ?

I've looked around, but I found nothing. I've done this :

scene.widthProperty().addListener(new ChangeListener<Number>() {
    @Override
    public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
        ConfigBusiness.getInstance().setScreenWidth(newValue.intValue());
    }
});

scene.heightProperty().addListener(new ChangeListener<Number>() {
    @Override
    public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
        ConfigBusiness.getInstance().setScreenHeight(newValue.intValue());
    }
});

But as you expect, everytime the width / height changes, it calls the function to save the value (in my case, in the registry, which results in many calls).

Is there a way to get the value only when the mouse button has been released ? Or maybe use another kind of listener (setOnMouseDragRelease or something like that) ?

EDIT : I want the user to be able to resize the application window, and once he releases the mouse button after resizing I would like to trigger an event (and not during the whole resizing process).

Thanks

EDIT 2 : Following a bit the idea of @Tomas Bisciak, I came up with this idea.

        scene.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if(!widthHasChanged()){
                    setWidthChanged(true);
                    System.out.println("Width changed");
                }
            }
        });

        scene.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if(!heightHasChanged()){
                    setHeightChanged(true);
                    System.out.println("Height changed");
                }
            }
        });


        scene.addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if(widthHasChanged()){
                    ConfigBusiness.getInstance().setScreenWidth(scene.getWidth());
                    System.out.println("Width changed > release");
                    setWidthChanged(false);
                }

                if(heightHasChanged()){
                    ConfigBusiness.getInstance().setScreenHeight(scene.getHeight());
                    System.out.println("Height changed > release");
                    setHeightChanged(false);
                }
            }
        });

I flagged the changes done during the resizing process (with the help of widthProperty and heightProperty) and set them to true if changed, and then when releasing the mouse, I set the values if they have changed.

The problem is that the last event MOUSE_RELEASED is not triggered. I see the output from the changeListeners but not the eventFilter. Any ideas ?

Jacks
  • 587
  • 5
  • 28
  • 1
    You want the resolution of the Monitor Screen or from the Application Window ?cause i see you are getting the application's window width and height. – GOXR3PLUS Aug 19 '16 at 16:40
  • From the appplication window. In fact, I just want the user to be able to resize the window of the app the way he wants, and keep that information for further uses. – Jacks Aug 22 '16 at 06:22

3 Answers3

1

Hook listener onto scene Handle mouse event anywhere with JavaFX (use MouseEvent.MOUSE_RELEASED) and on mouse release write values of the setScreenHeight/width(on every mouse release ),

if you want to only write values when drag happened with intention of resize , use boolean flag in change() "flag=true on change" methods to indicate that change has started, aferwards on mouse release just write values wherever you want and set flag to (flag=false).

Community
  • 1
  • 1
Tomas Bisciak
  • 2,801
  • 5
  • 33
  • 57
  • Can you please clarify your second paragraph ? "Use boolean flag in change()" => The function ´change()´ in a ´changeListener´ ? This is exactly what I'm looking for : writing values when the drag happened with intention of resize. – Jacks Aug 22 '16 at 06:37
  • @Jacks , yes in change listeners , every time you call method changed() set to true so you know that someone is currently resizing your scene.Now in your eventHandler when mouse gets released you check flag , if that flag is true means that before it was released one of the properties or both were changed , so now you can store or write your values (and then set flag back to false) . – Tomas Bisciak Aug 22 '16 at 10:27
  • @Jacks that boolean flag can be static and doesnt even have to be volatile since only JFXAT is accessing it. – Tomas Bisciak Aug 22 '16 at 10:31
  • Please see edit, I did it as you meant but upon resizing the window, the eventHandler is not triggered (only triggered inside the scene, so it seems that window borders are not taken in account). Otherwise, your solution would have been perfect. – Jacks Aug 22 '16 at 11:01
  • @Jacks Then you can use JNativeHook this global native listener , check out library its really easy to use , you can even click outside of the application and you still get events. https://github.com/kwhat/jnativehook use this instead of the eventHandler . This will work for you 100% – Tomas Bisciak Aug 22 '16 at 11:08
  • 1
    @Jacks https://github.com/kwhat/jnativehook/wiki/Mouse this is usage example, you should unregister it tho at application exit , use shutdown hook to do that , thats what i do :) – Tomas Bisciak Aug 22 '16 at 11:10
  • Thank you for your answer, unfortunately, and for the small feature it is compared to the whole app, I didn't want to use any external library for this. Anyway thank you very much for your answers, I found another way to do it. – Jacks Aug 22 '16 at 11:11
  • @Jacks no problem, its really usefull library tho , make sure you bookmark it. – Tomas Bisciak Aug 22 '16 at 11:12
  • I saw that, it is very interesting. It will be of some help for some personal projects, thanks :) – Jacks Aug 22 '16 at 11:14
1

If you want every time the mouse is released to get the resolution of the Monitor Screen here is the code:

Assuming you have the code for the Stage and Scene you can add a Listener for MouseReleased Event like this:

public double screenWidth ;
public double screenHeight;

.......

scene.setOnMouseReleased(m->{
     screenWidth = Screen.getPrimary().getBounds().getWidth();
     screenHeight = Screen.getPrimary().getBounds().getHeight();
});

......

In case you have an undecorated window that you resize it manually when the mouse is dragged i recommend you using setOnMouseDragged();

Assuming that you are doing the above this code for moving the window manually can be useful:

 public int initialX;
 public int initialY;
 public double screenWidth = Screen.getPrimary().getBounds().getWidth() ;
 public double screenHeight = Screen.getPrimary().getBounds().getHeight();

   setOnMousePressed(m -> {
                if (m.getButton() == MouseButton.PRIMARY) {
                    if (m.getClickCount() == 1) { // one Click
                        setCursor(Cursor.MOVE);
                        if (window.getWidth() < screenWidth ) {
                            initialX = (int) (window.getX() - m.getScreenX());
                            initialY = (int) (window.getY() - m.getScreenY());
                        } else
                            setFullScreen(false);
                    } else if (m.getClickCount() == 2) // two clicks
                        setFullScreen(true);

                }

            });

            setOnMouseDragged(m -> {
                if (window.getWidth() < screenWidth  && m.getButton() == MouseButton.PRIMARY) {
                    window.setX(m.getScreenX() + initialX);
                    window.setY(m.getScreenY() + initialY);
                }
            });

            setOnMouseReleased(m -> setCursor(Cursor.DEFAULT));
GOXR3PLUS
  • 6,877
  • 9
  • 44
  • 93
  • The question was about the application window, sorry I forgot to mention it clearly ... – Jacks Aug 22 '16 at 07:14
1

I finally found a way to accomplish "more or less" what I wanted. Here is the code for those who are looking for how to do it.

        ChangeListener<Number> resizeListener = new ChangeListener<Number>() {
            Timer timer = null; // used to schedule the saving task
            final long delay = 200; // the delay between 2 changes
            TimerTask task = null; // the task : saves resolution values

            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                // cancels the old task as a new one has been queried
                // at every change, we cancel the old task and start a new one
                if(task != null) task.cancel();
                // reset of the timer
                if(timer == null) timer = new Timer();

                task = new TimerTask() {
                    @Override
                    public void run() {
                            ConfigBusiness.getInstance().setScreenWidth(scene.getWidth());
                            ConfigBusiness.getInstance().setScreenHeight(scene.getHeight());
                            // stopping the timer once values are set
                            timer.cancel();
                            timer = null;
                            // stopping the task once values are set
                            task.cancel();
                            task = null;
                        }
                    };

                timer.schedule(task, delay);
            }
        };

        scene.widthProperty().addListener(resizeListener);
        scene.heightProperty().addListener(resizeListener);

I added some comments just to help understanding the way it works. During resizing, a timer schedules a task to retrieve the width / height of the window and is started.

If another changes incomes, then the task is "reset" in order to get only the last values set.

Once the values are retrieved, it is important to clear the timer and the task, else threads will continue running.

Thanks to all who gave me hints on how to do it, hope this helps !

Jacks
  • 587
  • 5
  • 28