4

I'm making an basic paint application in Javafx. And I'm wondering if there is some way to increase the draw speed of lines on the canvas.

public class MouseListener implements EventHandler<MouseEvent>{

    @Override
    public void handle(MouseEvent event) {


        if(event.getSource() == canvas){
            canvas.getParent().setCursor(Cursor.CROSSHAIR);

        }


        if(event.getEventType() == MouseEvent.MOUSE_PRESSED){

            x1 = event.getX(); 
            y1 = event.getY(); 

        }else if(event.getEventType() == MouseEvent.MOUSE_MOVED){


            pGraphics.reset();

            x2 = event.getX();
            y2 = event.getY();

            mouseClick = 0; 

            pGraphics.drawLine(x1, y1, x2, y2);

        }


    }


public void drawLine(double x1, double y1, double x2, double y2){

    gc.strokeLine(x1, y1, x2, y2);

}

public void reset()
{
    gc.clearRect(0,0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
}

As you can see the drawing is pretty straight forward using a MouseListener for detecting the (x1, y1) position where the line begins, and the same goes for setting the (x2, y2) postion where the line is supposed to end. As you see I clear the line after drawing, this is my intention since this is the function which are supposed to "show" where the line is supposed to go, e.g as in Microsoft Paint using line function. The issue of all this though, is that the line "laggs" behind the cursor, and quite much to when the cursor is moving at the right speed. So the question is: does this have something to do with my draw function, the canvas drawing function, the refresh rate of the mouseListener or something else entirely, or all together? Would really appreciate some suggestions to this.

Skarsh
  • 63
  • 1
  • 5

3 Answers3

3

I think you are following a completely wrong approach here. It would be much easier and much more efficient to just place a Line node on top of your canvas and just modify the geometry data of this line instead of constantly clearing the canvas and re-drawing the line. (You should also ask yourself whether using a Canvas here is the right thing to do anyway but that is something that only you can decide because you do not provide any information of what you actually want to do with your canvas.)

mipa
  • 10,369
  • 2
  • 16
  • 35
  • 1
    I am supposed to make a Paint application. So the canvas is my drawing board, where all lines, shapes and etc are drawn. I have made a layer system, such that for each layer, I add a Canvas and sets this canvas GraphicsContext to the current one. I have thougt about just adding them to a pane instead of using a Canvas. Do you think this would be a better approach? – Skarsh Jun 17 '16 at 16:47
  • 1
    It depends very much on the nature of your program. If its nature is more like a vector drawing program and you need to edit geometries after they have been drawn then using a pane is probably the better pick. – mipa Jun 18 '16 at 07:56
2

The issue is probably not the drawing speed, but instead input reaction lag similar to that which is discussed in the question: correct way to move a node by dragging in javafx 2?

Try some of the approaches from the answers to the linked question and see if it helps.

Note that, if this is the case, then whether you use a canvas or a scene graph won't really make a difference to the performance issue as the issue related to input event processing as opposed to the rendering system.

Related bug tracker ticket: Performance issue when tracking mouse events.

I see you have given a solution setting the undocumented JVM flag

-Djavafx.animation.fullspeed=true

How do I even begin to do this?

That wasn't a solution that I wrote and be a little careful that the undocumented flag might be removed or its behavior modified in future Java releases (though in this case I guess that is unlikely). Nevertheless it is worth trying.

To understand how to set command line flags, see: Proper usage of Java -D command-line parameters and also the java man page section titled: "-Dproperty=value".

It should be as simple as typing java -Djavafx.animation.fullspeed=true my package.MyMainClass or java -Djavafx.animation.fullspeed=true myjar.jar (substituting the My values for the appropriate values for your application of course).

Community
  • 1
  • 1
jewelsea
  • 150,031
  • 14
  • 366
  • 406
0

In your simple example it would be more eficient in the reset function to draw a line with the background color over the previous x1,y1,x2,y2 line and then draw the new line.

But, if you move 1 px, the user is not likely to notice the difference.

If the user just plays at the coordinates x1 = 50, y1 = 50 to x2'=51, y2'=50 or x2''=50, y2=51 you will still clear the whole canvas, which is quite dumb for only 1-2 changed pixels, for a canvas that could have thousands or millions of pixels.

But, either way, you could skip some redraws' without much impact to the user in order to optimize for some speed. So add a if to check that the difference between the previous x2 and y2, is greater than x pixels when compared to the current x2 and y2

Nicolae Natea
  • 1,185
  • 9
  • 14