I have a Canvas on which I'm drawing an Airplane , on a speficiec location(The first drawing works well) . While my program runs, I need to sample the airplane location from another server and update my plane location accordingly.
Everything works fine(parameters wise) , except nothing is being redrawned..
EDIT: Correction - a little smudge is being drawned on top of the original airplane, and then nothing else happens
My code:
public class AirplaneDrawer extends Canvas{
double x,y,rotate;
public void setCords(double x,double y,double rotate) {
if(x != this.x || y != this.y || rotate != this.rotate) {
this.x = x;
this.y = y;
this.rotate = rotate;
redraw();
}
}
public void redraw() {
GraphicsContext gc = getGraphicsContext2D();
String path = new String("M 323.193 226.645 c 39.244 24.41 75.644 47.053 115.706 71.978 c 7.687 -5.443 20.518 -14.485 33.308 -23.596 c 16.733 -11.923 36.27 -11.452 49.046 3.779 c 3.513 4.191 2.568 15.766 -0.705 21.426 c -23.705 40.994 -48.427 81.404 -73.095 121.833 c -4.729 7.745 -9.06 19.278 -21.177 13.509 c -12.203 -5.8 -28.746 -9.521 -27.842 -28.026 c 0.891 -18.185 3.495 -36.292 4.924 -50.249 c -40.704 -19.793 -79.74 -38.778 -119.825 -58.269 c -16.168 17.561 -22.275 40.532 -27.606 64.119 c -8.975 39.719 -18.474 79.324 -28.171 118.881 c -5.593 22.809 -12.452 26.109 -34.167 17.908 c -28.122 -10.606 -31.047 -14.689 -31.318 -45.384 c -0.605 -68.198 -1.514 -136.4 -1.325 -204.593 c 0.045 -15.865 -4.177 -25.531 -19.237 -32.95 c -30.238 -14.884 -60.119 -30.866 -88.548 -48.915 c -13.988 -8.884 -26.951 -21.77 -35.867 -35.727 C 3.526 110.834 15.381 90.43 40.637 91.746 c 17.786 0.931 36.644 4.67 52.618 12.229 c 32.58 15.413 63.735 33.905 95.022 51.921 c 8.735 5.028 15.083 4.992 23.944 0.068 c 64.671 -35.921 129.717 -71.172 194.611 -106.705 c 25.712 -14.075 46.608 -10.335 65.331 12.008 c 10.309 12.302 2.247 20.797 -6.506 28.579 c -35.89 31.91 -72.438 63.093 -107.682 95.687 C 344.877 197.641 334.677 212.878 323.193 226.645 Z");
double wid = getWidth()/247;
double hei = getHeight()/152;
gc.translate(wid*x,hei*y);
gc.scale(0.02,0.02);
gc.rotate(rotate);
gc.appendSVGPath(path);
gc.setFill(Color.BLACK);
gc.fill();
gc.stroke();
}
}
I thought maybe the GraphicContext remebers the last scale/translate/rotatation , so I've tried adding a second if
at the beggining of the if
in setCords
method, that if its not the first drawing, undo those steps backwards, but it didn't change anything.
EDIT: If I use this condition, then the smudge that I mentioned earlier in the first edit doesn't appear and nothing is being redrawned
if(this.x!=0 || this.y!= 0 || this.rotate != 0) {
GraphicsContext gc = getGraphicsContext2D();
double wid = getWidth()/247;
double hei = getHeight()/152;
gc.rotate(-this.rotate);
gc.scale(50, 50);
gc.translate(-wid*this.x,-hei*this.y);
}
What am I doing wrong? (I've debugged and saw the setCords
are being invoked with correct parameters as needed)
Note: I dont know if it matter, but the call to setCords
is being made in a separete Thread, so my program will continue as usual .
Thanks!
You mention:
Note: I dont know if it matter, but the call to
setCords
is being made in a separete Thread, so my program will continue as usual .
This does matter. From the documentation of GraphicsContext
:
A
Canvas
only contains oneGraphicsContext
, and only one buffer. If it is not attached to any scene, then it can be modified by any thread, as long as it is only used from one thread at a time. Once aCanvas
node is attached to a scene, it must be modified on the JavaFX Application Thread.Calling any method on the
GraphicsContext
is considered modifying its correspondingCanvas
and is subject to the same threading rules.
If you're on a background thread you can publish an action to the FX thread using Platform.runLater(Runnable)
. Take care not to flood the FX thread with too many actions, however. You may want to consider using an AnimationTimer
instead of, or possibly in conjunction with (using proper synchronization), a separate thread.
Also, be aware that drawing on a Canvas
does not clear anything previously drawn. To simulate movement you need to clear the appropriate area (or draw over it, e.g. with the background) and then redraw it in a different position. This can be as specific as only clearing/drawing over what's changed or as general as redrawing the entire canvas every time.