绘制基本形状
在BasicOpsTest
项目中(如图9-1所示),创建一个Canvas
,获取其GraphicsContext
,并在其上绘制一些基本形状。使用GraphicsContext
类的方法可以绘制线条、椭圆、圆角矩形、弧形和多边形。下载完整的BasicOpsTest
NetBeans项目的BasicOpsTest.zip文件。
示例9-1 在Canvas上绘制一些基本形状
package canvastest; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; import javafx.scene.shape.ArcType; import javafx.stage.Stage; public class BasicOpsTest extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("绘制操作测试"); Group root = new Group(); Canvas canvas = new Canvas(300, 250); GraphicsContext gc = canvas.getGraphicsContext2D(); drawShapes(gc); root.getChildren().add(canvas); primaryStage.setScene(new Scene(root)); primaryStage.show(); } private void drawShapes(GraphicsContext gc) { gc.setFill(Color.GREEN); gc.setStroke(Color.BLUE); gc.setLineWidth(5); gc.strokeLine(40, 10, 10, 40); gc.fillOval(10, 60, 30, 30); gc.strokeOval(60, 60, 30, 30); gc.fillRoundRect(110, 60, 30, 30, 10, 10); gc.strokeRoundRect(160, 60, 30, 30, 10, 10); gc.fillArc(10, 110, 30, 30, 45, 240, ArcType.OPEN); gc.fillArc(60, 110, 30, 30, 45, 240, ArcType.CHORD); gc.fillArc(110, 110, 30, 30, 45, 240, ArcType.ROUND); gc.strokeArc(10, 160, 30, 30, 45, 240, ArcType.OPEN); gc.strokeArc(60, 160, 30, 30, 45, 240, ArcType.CHORD); gc.strokeArc(110, 160, 30, 30, 45, 240, ArcType.ROUND); gc.fillPolygon(new double[]{10, 40, 10, 40}, new double[]{210, 210, 240, 240}, 4); gc.strokePolygon(new double[]{60, 90, 60, 90}, new double[]{210, 210, 240, 240}, 4); gc.strokePolyline(new double[]{110, 140, 110, 140}, new double[]{210, 210, 240, 240}, 4); } }
如示例9-1所示,Canvas
的宽度为300,高度为250。然后通过调用canvas.getGraphicsContext2D()
获取其GraphicsContext
。之后,通过调用strokeLine
、fillOval
、strokeArc
和fillPolygon
等方法进行一些基本的绘图操作。
您可以通过更改参数值来尝试此形状。当您这样做时,bezierCurveTo
将拉伸和拉动形状。
之后,红色和黄色的RadialGradient
提供了出现在背景中的圆形图案。
示例 9-4 绘制 RadialGradient
private void drawRadialGradient(Color firstColor, Color lastColor) { gc.setFill(new RadialGradient(0, 0, 0.5, 0.5, 0.1, true, CycleMethod.REFLECT, new Stop(0.0, firstColor), new Stop(1.0, lastColor))); gc.fill(); }
在这里,GraphicsContext
的setFill
方法接受一个RadialGradient
对象作为其参数。同样,您可以尝试不同的值,或者根据您的喜好传入不同的颜色。
LinearGradient
将自定义的 "D" 形状从蓝色渐变到绿色:
示例 9-5 绘制 LinearGradient
private void drawLinearGradient(Color firstColor, Color secondColor) { LinearGradient lg = new LinearGradient(0, 0, 1, 1, true, CycleMethod.REFLECT, new Stop(0.0, firstColor), new Stop(1.0, secondColor)); gc.setStroke(lg); gc.setLineWidth(20); gc.stroke(); }
此代码将GraphicsContext
的描边设置为使用LinearGradient
,然后使用gc.stroke()
渲染图案。
最后,多彩的阴影通过在GraphicContext
对象上调用applyEffect
来提供。
示例 9-6 添加 DropShadow
private void drawDropShadow(Color firstColor, Color secondColor, Color thirdColor, Color fourthColor) { gc.applyEffect(new DropShadow(20, 20, 0, firstColor)); gc.applyEffect(new DropShadow(20, 0, 20, secondColor)); gc.applyEffect(new DropShadow(20, -20, 0, thirdColor)); gc.applyEffect(new DropShadow(20, 0, -20, fourthColor)); }
如示例 9-6所示,通过创建具有指定颜色的DropShadow
对象,并将其传递给GraphicsContext
对象的applyEffect
方法来应用此效果。
与用户交互
在下面的演示中(项目CanvasDoodleTest
),一个蓝色的正方形出现在屏幕上,当用户拖动鼠标在其表面上时,它将慢慢被擦除。下载完整的CanvasDoodleTest
NetBeans项目的CanvasDoodleTest.zip文件
您已经了解了如何创建基本形状和渐变,因此Example 9-7
中的代码只关注与用户交互的部分。
例9-7 与用户交互
... private void reset(Canvas canvas, Color color) { GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFill(color); gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); } @Override public void start(Stage primaryStage) { ... final GraphicsContext gc = canvas.getGraphicsContext2D(); ... // 当用户拖动鼠标时,清除部分内容 canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent e) { gc.clearRect(e.getX() - 2, e.getY() - 2, 5, 5); } }); // 当用户双击时,用蓝色矩形填充画布 canvas.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { if (t.getClickCount() >1) { reset(canvas, Color.BLUE); } } }); ...
Example 9-7
定义了一个reset
方法,用默认的蓝色填充整个矩形。但最有趣的代码出现在被重写的start
方法中,用于与用户交互。第一个被注释的部分添加了一个事件处理程序,以处理用户拖动鼠标时的MouseEvent
对象。每次拖动时,调用GraphicsContext
对象的clearRect
方法,传入当前鼠标坐标以及要清除的区域的大小。在此过程中,背景渐变将显示出来,如Figure 9-4
所示。
剩余的代码只是计算点击次数,并在用户双击鼠标时将蓝色正方形重置为初始状态。
因为两个图层直接放在一起,只有最上面的Canvas
会处理鼠标点击事件。要将特定的图层移到堆栈的前面,只需从屏幕顶部的ChoiceBox
组件中选择它。
示例9-10 选择图层
private void createChoiceBox(){ cb = new ChoiceBox(); cb.setItems(FXCollections.observableArrayList( "图层1是绿色", "图层2是蓝色")); cb.getSelectionModel().selectedItemProperty(). addListener(new ChangeListener(){ @Override public void changed(ObservableValue o, Object o1, Object o2){ if(o2.toString().equals("图层1是绿色")){ layer1.toFront(); }else if(o2.toString().equals("图层2是蓝色")){ layer2.toFront(); } } }); cb.setValue("图层1是绿色"); }
如示例9-10所示,ChoiceBox
上注册了一个ChangleListener
,通过在适当的Canvas
上调用toFront()
将选定的图层置于前景。在添加了许多蓝色和绿色圆圈后,通过切换图层,您将能够通过观察圆圈边缘来判断哪个图层已经移到前面。 图9-6和图9-7展示了这个效果。
选择图层的能力在软件应用程序中很常见,例如图像处理程序。而且,由于每个Canvas
对象都是一个Node
,您可以自由地应用在其他组件上的所有标准变换和视觉效果。