2012-07-30 18 views
6

Chciałbym wiedzieć, jak narysować półkole w JavaFX. Próbowałem użyć Shape i QuadCurve, ale nie mogłem stworzyć idealnego półkola.Narysuj pół pierścień - JavaFX

Oto obraz tego, co staram się rysować:

enter image description here

Odpowiedz

10

obraz jesteś połączony jest właściwie pół-ring. Możesz pobrać go w JavaFX, rysując zagnieżdżone 2 łuki i niektóre linie. Ale moim preferowanym sposobem jest użycie Path.

public class SemiDemo extends Application { 

    @Override 
    public void start(Stage primaryStage) { 

     Group root = new Group(); 
     root.getChildren().add(drawSemiRing(120, 120, 100, 50, Color.LIGHTGREEN, Color.DARKGREEN)); 
     root.getChildren().add(drawSemiRing(350, 350, 200, 30, Color.LIGHTSKYBLUE, Color.DARKBLUE)); 

     Scene scene = new Scene(root, 300, 250); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private Path drawSemiRing(double centerX, double centerY, double radius, double innerRadius, Color bgColor, Color strkColor) { 
     Path path = new Path(); 
     path.setFill(bgColor); 
     path.setStroke(strkColor); 
     path.setFillRule(FillRule.EVEN_ODD); 

     MoveTo moveTo = new MoveTo(); 
     moveTo.setX(centerX + innerRadius); 
     moveTo.setY(centerY); 

     ArcTo arcToInner = new ArcTo(); 
     arcToInner.setX(centerX - innerRadius); 
     arcToInner.setY(centerY); 
     arcToInner.setRadiusX(innerRadius); 
     arcToInner.setRadiusY(innerRadius); 

     MoveTo moveTo2 = new MoveTo(); 
     moveTo2.setX(centerX + innerRadius); 
     moveTo2.setY(centerY); 

     HLineTo hLineToRightLeg = new HLineTo(); 
     hLineToRightLeg.setX(centerX + radius); 

     ArcTo arcTo = new ArcTo(); 
     arcTo.setX(centerX - radius); 
     arcTo.setY(centerY); 
     arcTo.setRadiusX(radius); 
     arcTo.setRadiusY(radius); 

     HLineTo hLineToLeftLeg = new HLineTo(); 
     hLineToLeftLeg.setX(centerX - innerRadius); 

     path.getElements().add(moveTo); 
     path.getElements().add(arcToInner); 
     path.getElements().add(moveTo2); 
     path.getElements().add(hLineToRightLeg); 
     path.getElements().add(arcTo); 
     path.getElements().add(hLineToLeftLeg); 

     return path; 
    } 

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

Zapoznaj się z Shape API JavaFX, aby uzyskać więcej informacji o kształtach używanych w kodzie.
ekranu:

enter image description here

+0

Rok, idealny! : D Dokładnie tego potrzebuję ^^ Dziękuję bardzo! – AwaX

+0

Czy wiesz, czy istnieje prosty sposób modyfikacji punktu obrotu ścieżki? – AwaX

+0

@AwaX path.setRotate (45); –

4

Sugestie:

  • Jeśli nie potrzebujemy pełnej ścieżki konspektu, można po prostu użyć Łuk.
  • Jeśli nie potrzebujesz wypełnienia łuku i chcesz tylko prześledzić ścieżkę obrysu łuku, ustaw wypełnienie łuku na wartość zerową.
  • Jeśli chcesz, aby ścieżka konturu łuku była gruba, ustaw parametry suwu na łuku.
  • Jeśli potrzebujesz grubego łuku, który również jest zarysowany, najlepiej jest zdefiniować pełny łuk, jak w odpowiedzi Uluka.

Przykładowy kod:

import javafx.application.Application; 
import javafx.scene.*; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.*; 
import javafx.stage.Stage; 

public class SemiCircleSample extends Application { 
    @Override public void start(Stage stage) { 
    Arc arc = new Arc(50, 50, 25, 25, 0, 180); 
    arc.setType(ArcType.OPEN); 
    arc.setStrokeWidth(10); 
    arc.setStroke(Color.CORAL); 
    arc.setStrokeType(StrokeType.INSIDE); 
    arc.setFill(null); 

    stage.setScene(new Scene(new Group(arc), 100, 80)); 
    stage.show(); 
    } 

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

Dziękuję, ale to pełne półkole, co chcę narysować to półkole puste w środku. W poprzednim poście umieściłem przykład pokazujący dokładnie to, co próbuję narysować. – AwaX

+0

Zaktualizowana odpowiedź w celu zademonstrowania rysowania łuku z określonym obrysem i bez wypełnienia (które wygeneruje obraz pół-pierścieniowy). – jewelsea

+0

Dziękuję bardzo za twoją aktualizację, twoje rozwiązanie jest wygodniejsze, ale nie możesz wypełnić łuku, tak jak powiedziałeś, więc myślę, że wezmę inne rozwiązanie. – AwaX

0

Path.arcTo() parametru SweepAngle odnosi się do stopnia obrotu, jeśli sweepAngle jest dodatni łuku ruchu wskazówek zegara, jeśli sweepAngle jest ujemny łuku w kierunku przeciwnym.

Kod ten jest używany w moim środowisku produkcyjnym, to zwraca pierścień półokrąg użyciu bitmapy, ścieżka idzie w prawo na zewnętrznym promieniu, a przeciwnie do ruchu wskazówek zegara na wewnętrznym promieniu:

drawpercent = 0.85; //this draws a semi ring to 85% you can change it using your code. 
DegreesStart = -90; 
DegreesRotation = 180; 

radiusPathRectF = new android.graphics.RectF((float)CentreX - (float)Radius, (float)CentreY - (float)Radius, (float)CentreX + (float)Radius, (float)CentreY + (float)Radius); 
innerradiusPathRectF = new android.graphics.RectF((float)CentreX - (float)InnerRadius, (float)CentreY - (float)InnerRadius, (float)CentreX + (float)InnerRadius, (float)CentreY + (float)InnerRadius); 

Path p = new Path(); //TODO put this outside your draw() function, you should never have a "new" keyword inside a fast loop. 

       degrees = (360 + (DegreesStart)) % 360; 
       radians = (360 - degrees + 90) * Math.PI/180.0; 
       //radians = Math.toRadians(DegreesStart); 
       int XstartOuter = (int)Math.round((Math.cos(radians) * Radius + CentreX)); 
       int YstartOuter = (int)Math.round((Math.sin(-radians)* Radius + CentreY)); 
       int XstartInner = (int)Math.round((Math.cos(radians) * InnerRadius + CentreX)); 
       int YstartInner = (int)Math.round((Math.sin(-radians) * InnerRadius + CentreY)); 

       degrees = (360 + (DegreesStart + drawpercent * DegreesRotation)) % 360; 
       //radians = degrees * Math.PI/180.0; 
       radians = (360 - degrees + 90) * Math.PI/180.0; 
       //radians = Math.toRadians(DegreesStart + drawpercent * DegreesRotation); 
       int XendOuter = (int)Math.round((Math.cos(radians) * Radius + CentreX)); 
       int YendOuter = (int)Math.round((Math.sin(-radians) * Radius + CentreY)); 
       int XendInner = (int)Math.round((Math.cos(radians) * InnerRadius + CentreX)); 
       int YendInner = (int)Math.round((Math.sin(-radians) * InnerRadius + CentreY)); 

       //draw a path outlining the semi-circle ring. 
       p.moveTo(XstartInner, YstartInner); 
       p.lineTo(XstartOuter, YstartOuter); 
       p.arcTo(radiusPathRectF, (float)DegreesStart - (float)90, (float)drawpercent * (float)DegreesRotation); 
       p.lineTo(XendInner, YendInner); 
       p.arcTo(innerradiusPathRectF, (float)degrees - (float)90, -1 * (float)drawpercent * (float)DegreesRotation); 
       p.close(); 

       g.clipPath(p); 

       g.drawBitmap(bitmapCircularBarImage, bitmapRect0, bitmapRectXY, paint); 
2

Jako eksperyment próbowałem zrobić to samo na płótnie. To jest to, co wymyśliłem, dzięki czemu korzystanie z RadialGradient a funkcja GraphicsContext.fillArc:

/** 
* 
* @param x Coordinate x of the centre of the arc 
* @param y Coordinate y of the centre of the arc 
* @param outer Outer radius of the arc 
* @param innerPercentage Inner radius of the arc, from 0 to 1 (as percentage) 
* @param arcStartAngle Start angle of the arc, in degrees 
* @param arcExtent Extent of the arc, in degrees 
*/ 
private void drawSemiCircle(float x, float y, float outer, float innerPercentage, float arcStartAngle, float arcExtent) { 
    RadialGradient rg = new RadialGradient(
      0, 
      0, 
      x, 
      y, 
      outer, 
      false, 
      CycleMethod.NO_CYCLE, 
      new Stop((innerPercentage + (.0 * innerPercentage)), Color.TRANSPARENT), 
      new Stop((innerPercentage + (.1 * innerPercentage)), Color.RED), 
      new Stop((innerPercentage + (.6 * innerPercentage)), Color.YELLOW), 
      new Stop((innerPercentage + (1 * innerPercentage)), Color.GREEN) 
    ); 
    gc.setFill(rg); 
    gc.fillArc(
      x - outer, 
      y - outer, 
      outer * 2, 
      outer * 2, 
      arcStartAngle, 
      arcExtent, 
      ArcType.ROUND 
    ); 
} 

Kluczowe punkty Oto typ łukowy ArcType.ROUND i wykorzystanie Color.TRANSPARENT jako pierwszego koloru.

Wtedy może on być stosowany coś wzdłuż linii:

drawSemiCircle(100, 100, 100, .5f, -45, 270); 

Nie jest to idealne rozwiązanie, ale pracował dla mnie.