文档



JavaFX:使用JavaFX图形
9 使用Canvas API(发布版8)

绘制基本形状

BasicOpsTest项目中(如图9-1所示),创建一个Canvas,获取其GraphicsContext,并在其上绘制一些基本形状。使用GraphicsContext类的方法可以绘制线条、椭圆、圆角矩形、弧形和多边形。下载完整的BasicOpsTest NetBeans项目的BasicOpsTest.zip文件。

图9-1 在Canvas上绘制形状

图9-1的描述
图9-1的描述

示例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。之后,通过调用strokeLinefillOvalstrokeArcfillPolygon等方法进行一些基本的绘图操作。

9 使用Canvas API(版本8)

您可以通过更改参数值来尝试此形状。当您这样做时,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();
}

在这里,GraphicsContextsetFill方法接受一个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文件

图9-3 与用户交互

图9-3的描述如下
图9-3的描述

您已经了解了如何创建基本形状和渐变,因此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所示。

图9-4 清除矩形

图9-4的描述如下
图9-4的描述

剩余的代码只是计算点击次数,并在用户双击鼠标时将蓝色正方形重置为初始状态。

9 使用Canvas API(发布版8)

因为两个图层直接放在一起,只有最上面的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展示了这个效果。

图9-6 选择图层1

图9-6的描述
"图9-6 选择图层1"的描述

图9-7 选择图层2

图9-7的描述
"图9-7 选择图层2"的描述

选择图层的能力在软件应用程序中很常见,例如图像处理程序。而且,由于每个Canvas对象都是一个Node,您可以自由地应用在其他组件上的所有标准变换和视觉效果。

关闭窗口

目录

JavaFX: 使用JavaFX图形

展开 折叠