package canvastest; import javafx.application.Application; import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.geometry.Bounds; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.control.CheckBox; import javafx.scene.control.ChoiceBox; import javafx.scene.effect.*; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import javafx.scene.shape.ArcType; import javafx.scene.shape.Rectangle; import javafx.scene.shape.StrokeLineJoin; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.stage.Stage; public class ManualRenderModifiersTest extends Application { public static void main(String[] args) { launch(args); } enum RenderType { FILL_RECT, STROKE_RECT, FILL_OVAL, STROKE_OVAL, FILL_ROUNDRECT, STROKE_ROUNDRECT, FILL_ARC, STROKE_ARC, FILL_STRING, STROKE_STRING, FILL_SHAPE, STROKE_SHAPE, } CheckBox cbBlend; CheckBox cbClip; CheckBox cbEffect; CheckBox cbTransform; CheckBox cbOpacity; ChoiceBox cbRenderType; Canvas canvas; Text text; @Override public void start(Stage primaryStage) { primaryStage.setTitle("Multiple rendering modifiers Canvas Test"); Group root = new Group(); cbBlend = new CheckBox("blend DIFFERENCE"); cbClip = new CheckBox("clip"); cbEffect = new CheckBox("blur effect"); cbTransform = new CheckBox("rotate transform"); cbOpacity = new CheckBox("extra alpha"); cbRenderType = new ChoiceBox(); cbRenderType.getItems().addAll(RenderType.values()); cbRenderType.getSelectionModel().selectFirst(); InvalidationListener listener = new InvalidationListener() { @Override public void invalidated(Observable arg0) { reRender(); } }; cbBlend.selectedProperty().addListener(listener); cbClip.selectedProperty().addListener(listener); cbEffect.selectedProperty().addListener(listener); cbTransform.selectedProperty().addListener(listener); cbOpacity.selectedProperty().addListener(listener); cbRenderType.valueProperty().addListener(listener); canvas = new Canvas(200, 200); canvas.setTranslateX(10); canvas.setTranslateY(20); Rectangle bg = new Rectangle(10, 20, 200, 200); bg.setFill(Color.WHITE); text = new Text(""); text.setY(15); VBox controls = new VBox(10); controls.getChildren().addAll(cbBlend, cbClip, cbEffect, cbTransform, cbOpacity, cbRenderType); controls.setTranslateX(220); controls.setTranslateY(20); root.getChildren().addAll(bg, canvas, text, controls); reRender(); Scene scene = new Scene(root, 400, 230); scene.setFill(Color.gray(0.85)); primaryStage.setScene(scene); primaryStage.show(); } private void reRender() { boolean doBlend = cbBlend.isSelected(); boolean doClip = cbClip.isSelected(); boolean doEffect = cbEffect.isSelected(); boolean doTransform = cbTransform.isSelected(); boolean doOpacity = cbOpacity.isSelected(); RenderType renderType = cbRenderType.getValue(); render(canvas, renderType, doBlend, doClip, doEffect, doTransform, doOpacity); String label = renderType.toString(); if (doBlend) label += ", DIFF"; if (doClip) label += ", clip"; if (doEffect) label += ", blur"; if (doTransform) label += ", rotate"; if (doOpacity) label += ", ea"; text.setText(label); text.setX(0); Bounds bounds = text.getBoundsInLocal(); text.setX(100 - (bounds.getMinX() + bounds.getMaxX()) / 2.0); } private static void render(Canvas c, RenderType renderType, boolean doBlend, boolean doClip, boolean doEffect, boolean doTransform, boolean doOpacity) { GraphicsContext gc = c.getGraphicsContext2D(); gc.save(); gc.clearRect(0, 0, 200, 200); gc.setLineWidth(renderType == RenderType.STROKE_STRING ? 6 : 20); gc.setLineJoin(StrokeLineJoin.ROUND); gc.setFont(Font.font("sans-serif", FontWeight.BOLD, 90)); Paint p = Color.rgb(0, 0, 255, 0.75); gc.setFill(p); gc.setStroke(p); if (doBlend) { gc.setGlobalBlendMode(BlendMode.DIFFERENCE); } if (doClip) { gc.beginPath(); gc.arc(100, 100, 80, 80, 0, 360); gc.clip(); } if (doEffect) { gc.setEffect(new GaussianBlur(10)); } if (doTransform) { gc.translate(100, 100); gc.rotate(85); gc.translate(-100, -100); } if (doOpacity) { gc.setGlobalAlpha(0.8); } renderObj(gc, renderType, 10, 10, 90, 90); renderObj(gc, renderType, 40, 40, 90, 90); renderObj(gc, renderType, 70, 70, 90, 90); renderObj(gc, renderType, 100, 100, 90, 90); gc.restore(); } private static void renderObj(GraphicsContext gc, RenderType renderType, double x, double y, double w, double h) { switch (renderType) { case FILL_RECT: gc.fillRect(x, y, w, h); break; case STROKE_RECT: gc.strokeRect(x+10, y+10, w-20, h-20); break; case FILL_OVAL: gc.fillOval(x, y, w, h); break; case STROKE_OVAL: gc.strokeOval(x+10, y+10, w-20, h-20); break; case FILL_ROUNDRECT: gc.fillRoundRect(x, y, w, h, 40, 40); break; case STROKE_ROUNDRECT: gc.strokeRoundRect(x+10, y+10, w-20, h-20, 40, 40); break; case FILL_ARC: gc.fillArc(x, y, w, h, 75, 270, ArcType.ROUND); break; case STROKE_ARC: gc.strokeArc(x+10, y+10, w-20, h-20, 75, 270, ArcType.ROUND); break; case FILL_STRING: gc.fillText("FX", x, y+90); break; case STROKE_STRING: gc.strokeText("FX", x, y+90); break; case STROKE_SHAPE: x += 10; y += 10; w -= 20; h -= 20; // NOBREAK case FILL_SHAPE: gc.beginPath(); gc.moveTo(x, y); gc.bezierCurveTo(x+w*1/3, y+h*1/5, x+w*2/3, y-h*1/5, x+w, y); gc.lineTo(x+w, y+h); gc.quadraticCurveTo(x+w/2, y+h*3/4, x, y+h); gc.closePath(); if (renderType == RenderType.FILL_SHAPE) { gc.fill(); } else { gc.stroke(); } break; default: throw new InternalError("Unrecognized render type: "+renderType); } } }