2
\$\begingroup\$

(See the next version here.)

Intro

I have this tiny JavaFX program that shows a 800x600 pixel canvas. You are supposed to drag the mouse within the canvas. When you are done dragging, the program will print in the standard output the number of frames per second.

For example, my system prints

196 frames in 1566 milliseconds, refresh rate of 125.15964240102171 Hz.

Code

com.github.coderodde.javafx.mouseupdaterate.MouseUpdateRateFinder.java:

package com.github.coderodde.javafx.mouseupdaterate;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public final class MouseUpdateRateFinder extends Application {
    
    private static final int SCREEN_WIDTH = 800;
    private static final int SCREEN_HEIGHT = 600;
    
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        Group root = new Group();
        Canvas canvas = new Canvas(SCREEN_WIDTH, SCREEN_HEIGHT);
        
        canvas.addEventHandler(MouseEvent.ANY, new MyMouseListener());
        
        root.getChildren().add(canvas);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }
    
    private static final class MyMouseListener implements EventHandler<MouseEvent> {

        private long mouseButtonEventStart;
        private int frameCounter;
        
        @Override
        public void handle(MouseEvent t) {
            EventType<? extends MouseEvent> eventType = t.getEventType();
            
            if (eventType.equals(MouseEvent.MOUSE_PRESSED)) {
                mouseButtonEventStart = System.currentTimeMillis();
                frameCounter = 0;
            } else if (eventType.equals(MouseEvent.MOUSE_RELEASED)) {
                long duration = System.currentTimeMillis() 
                              - mouseButtonEventStart;
                
                System.out.println(
                        frameCounter 
                                + " frames in " 
                                + duration 
                                + " milliseconds, refresh rate of " 
                                + computeRefreshRate(duration, frameCounter) 
                                + " Hz.");
            } else if (eventType.equals(MouseEvent.MOUSE_DRAGGED)) {
                frameCounter++;
            }
        }
        
        private double computeRefreshRate(long duration, int frameCounter) {
            double t = ((double) duration) / 1000.0;
            return ((double) frameCounter) / t;
        }
    }
}

Critique request

Is there any room for improvement? Please tell me anything.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Your start doesn't actually throw any checked exceptions, so remove throw Exception (don't worry; this doesn't break override compatibility).

Writing an "everything handler" that then switches on event type is an anti-pattern; just register three separate handlers. You can use the new(ish) Java method reference sugar for this purpose. It's not strictly necessary to have a separate class but it's probably a good idea to keep it out of separation of concerns.

Might as well use nanoTime() instead of currentTimeMillis() for higher precision.

Avoid repeated-concatenation formatting; instead just use printf. When you do this, you should limit floating-point precision in your output.

Suggested

package com.github.coderodde.javafx.mouseupdaterate;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public final class MouseUpdateRateFinder extends Application {

    private static final int SCREEN_WIDTH = 800;
    private static final int SCREEN_HEIGHT = 600;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Group root = new Group();

        MyMouseListener listener = new MyMouseListener();

        Canvas canvas = new Canvas(SCREEN_WIDTH, SCREEN_HEIGHT);
        canvas.addEventHandler(MouseEvent.MOUSE_PRESSED, listener::handlePressed);
        canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED, listener::handleDragged);
        canvas.addEventHandler(MouseEvent.MOUSE_RELEASED, listener::handleReleased);

        root.getChildren().add(canvas);
        stage.setScene(new Scene(root));
        stage.show();
    }

    private static final class MyMouseListener {
        private long dragStartNs;
        private int frameCounter;


        public void handlePressed(MouseEvent t) {
            dragStartNs = System.nanoTime();
            frameCounter = 0;
        }

        public void handleDragged(MouseEvent t) {
            frameCounter++;
        }

        public void handleReleased(MouseEvent t) {
            double duration = 1e-9*(System.nanoTime() - dragStartNs);

            System.out.printf(
                "%d frames in %.2f s, refresh rate of %.1f Hz%n",
                frameCounter, duration, frameCounter / duration);
        }
    }
}

Output

155 frames in 1.61 s, refresh rate of 96.0 Hz
184 frames in 1.46 s, refresh rate of 126.2 Hz
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.