2

I'm creating a healthbar with 2 rectangles overlapping each other. The inner shows the current health, the outer shows the total health.

Problem

The healthbar is blurry.

What I've got so far

I've read about e. g. having to add 0.5, but it only solves the problem partially.

A screenshot, top image is without the 0.5, bottom image is with the 0.5 added.

enter image description here

Here's the code:

private class HealthBar extends Pane {

    Rectangle outerHealthRect;
    Rectangle innerHealthRect;

    public HealthBar() {

        double height = 10;

        double outerWidth = 60;
        double innerWidth = 40;

        // using 0.5, otherwise it would be blurry
        double x=snap( 0.0);
        double y=snap( 0.0);

        outerHealthRect = new Rectangle( x, y, outerWidth, height);
        outerHealthRect.setStroke(Color.BLACK);
        outerHealthRect.setFill(Color.WHITE);

        innerHealthRect = new Rectangle( x, y, innerWidth, height);
        innerHealthRect.setStroke(Color.TRANSPARENT);
        innerHealthRect.setFill(Color.LIMEGREEN);

        getChildren().addAll( outerHealthRect);
        getChildren().addAll( innerHealthRect);

    }

    public void setValue( double value) {
        innerHealthRect.setWidth( snap( outerHealthRect.getWidth() * value));
    }

    private double snap( double value) {
        return (int) value + 0.5;
    }
}

After I applied scaling for debug purposes it became obvious that the transparent stroke isn't considered as transparent line of the same width like a stroke with color:

enter image description here

Questions

  • Is there an option to snap to pixels, i. e. have sharp pixels in general without having to mess around with 0.5?
  • How can I make the transparent stroke the same width as the outer stroke?

I could try a different approach with a canvas, but these are general questions which affect the way you have to set up a JavaFX application.

Thank you very much.

Community
  • 1
  • 1
Roland
  • 18,114
  • 12
  • 62
  • 93
  • In case you haven't seen this, http://stackoverflow.com/a/11887786/2855515 – brian Jan 27 '15 at 13:15
  • Thank you, I haven't seen it, but when I searched the web I found both the snapToPixels and that you should use INSIDE or OUTSIDE instead of CENTERED. These give me the best results so far. But there's still blurryness after I apply them, e. g. on the right side of the green rectangle is a single line of blur. – Roland Jan 27 '15 at 14:21

1 Answers1

2

Don't snap the fill. The question I linked to explains that lines are drawn on the pixels(through the middle - which takes a whole pixel), which means +0.5 since the coords are between pixels.

Fills need to be drawn over the whole pixel to the space between them.

enter image description here

public HealthBar() {

    double height = 10;

    double outerWidth = 60;
    double innerWidth = 40;

    double x=10,y=10;//away from pane edge just to see better

    outerHealthRect = new Rectangle( snap(x), snap(y), outerWidth, height);
    outerHealthRect.setStroke(Color.BLACK);
    outerHealthRect.setFill(Color.WHITE);

    //just move green bar right a bit to see edges
    //and move it down 1 pix so it's not over the black edge
    //this means height is -1 as well
    innerHealthRect = new Rectangle( x+11, y+1, innerWidth, height-1);
    innerHealthRect.setFill(Color.LIMEGREEN);
    //no need to draw transparent anything

    getChildren().addAll( outerHealthRect);
    getChildren().addAll( innerHealthRect);

}
brian
  • 10,619
  • 4
  • 21
  • 79