2012-07-30 81 views
6

我想知道如何在JavaFX中绘制半圆。我尝试使用Shape和QuadCurve,但我无法制作完美的半圆。绘制半环 - JavaFX

这里是什么,我想画一幅画:

enter image description here

回答

10

您链接的图片实际上是一个半环。您可以通过绘制嵌套的2个弧和一些线在JavaFX中获得它。但我最喜欢的方式是使用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); 
    } 
} 

有关代码中使用的形状的更多信息,请参阅JavaFX的Shape API
截图:

enter image description here

+0

年,完美! :D这正是我需要的^^非常感谢! – AwaX 2012-07-30 12:14:35

+0

您是否知道是否有简单的方法来修改路径的旋转点? – AwaX 2012-07-31 11:59:51

+0

@AwaX path.setRotate(45); – 2012-07-31 12:26:05

4

建议:

  • 如果你并不需要一个完整的大纲路径,你可以只使用一个弧。
  • 如果您不需要填充的圆弧并且只想跟踪圆弧的轮廓路径,则将圆弧的填充设置为空。
  • 如果您想让粗线的粗线路径较粗,则在弧上设置笔触参数。
  • 如果你需要一个粗略的圆弧,那么最好定义一个完整的圆弧,就像Uluk的答案一样。

示例代码:

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

谢谢你,但它是一个完整的半圆,我想绘制的是一个空心的半圆。我在之前的文章中包含了一个示例,显示了我正在尝试绘制的内容。 – AwaX 2012-07-30 11:39:27

+0

已更新答案,以演示绘制具有指定笔画和无填充(将生成半环图像)的弧线。 – jewelsea 2012-07-30 17:10:18

+0

非常感谢你的更新,你的解决方案更方便,但你不能像你说的那样填满弧线,所以我想我会采取其他解决方案。 – AwaX 2012-07-31 11:57:10

0

Path.arcTo()的参数SweepAngle指旋转的程度,如果是sweepAngle正弧是顺时针,如果sweepAngle是负弧是逆时针方向。

该代码在我的生产环境中使用,它绘制使用位图图像半圆形环,路径变为顺时针上的外半径,和内半径逆时针:

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

作为一个实验,我试图在Canvas上做同样的事情。这是我想出了,利用一个的RadialGradient和功能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 
    ); 
} 

这里的关键点是弧型的ArcType.ROUND和使用Color.TRANSPARENT作为第一种颜色。

然后,它可以用于一些沿线:

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

这不是一个完美的解决方案,但它为我工作。