javafx canvas_教程:JavaFX的Canvas API概览
javafx canvas
Carl Dea出现在11月的《 JAX杂志》上 ,使用Java的富客户端技术JavaFX花费了几个小时。
我最近参加了 去年 10月 由 Oracle 主办 的 JavaOne 2012会议 。 我的主要目标是将精力集中在与客户端Java有关的所有事情上,即使会话的标题中不包含“ JavaFX”。 令我惊讶的是,我收到的收益远远超出了讨价还价。 我参加了涉及 Dolphin , Griffon , Java Embedded , JavaFX 8等 技术的会议 。
我不禁为新的 JavaFX 8的3D API 感到垂涎三尺 。 但是, 我的 另一项 意图是查看 JavaFX 2.2 当前 版本 中添加的许多新功能 。 特别是,想到的一项功能是备受期待的Canvas API。 在本文中,您将了解使用JavaFX的 Canvas API 时的一些性能特征 ,稍后,我将分享一些代码,并教您如何仅在JavaFX的场景图上使用Canvas API而不是基于矢量来构建动画时钟。对应版本(JavaFX 2.1和更早版本)。
在JavaOne 2012大会上的许多JavaFX会议中,特别 引人注目的一届 是 Richard Bair的 ( CON6784 – JavaFX图形技巧和窍门 )。 JavaFX架构师Bair先生与流行的桌面操作系统(Windows,Linux / Ubuntu和Mac OS X)上的所有主要浏览器相比,讨论了JavaFX 2和JavaFX 8的图形渲染性能。 基准测试结果(遵循 GUIMark 2 )按“矢量”和“位图”图形渲染策略分类。 大多数HTML5 Web开发人员都熟悉,使用“矢量”呈现策略只是 SVG (可缩放矢量图形的XML表示)的 同义词 。 除此之外,“位图”呈现策略等效于使用流行的 HTML5 Canvas API( 使用JavaScript语言)的使用 。
当涉及矢量渲染策略时,性能数据表明JavaFX在Mac OS X上的Safari浏览器除外,其表现优于所有竞争对手。类似地,当涉及位图渲染策略时,性能指标表明JavaFX Canvas API的性能优于所有的浏览器。 Bair先生在解释何时,为什么以及如何在两种渲染策略之间进行选择方面做得非常出色。 Bair先生还指出,在某些情况下,JavaFX矢量图形甚至可以胜过JavaFX画布。 他还建议,当使用一种技术而不是另一种技术时,真正获得更准确图片的唯一方法是分析应用程序。 当然,他的演讲中讨论了更多内容。 但是,在本文中,我仅希望指出与Canvas API有关的信息。
在JavaFX的世界中,场景图主要基于“矢量”渲染策略,该策略将形状和路径计算为易于缩放的场景图节点。 对于那些回想起JavaFX 2.2之前的开发人员,您会记得何时没有能力处理位图图形(像素推送)。 您可能想知道,“如何使用“位图”策略在基于JavaFX矢量的场景图上进行渲染?” 自JavaFX 2.2发布以来,JavaFX团队创建了Canvas API。 Canvas API实际上是一个称为 Canvas 类 的JavaFX节点 。 由于 Canvas 类是从 javafx.scene.Node 类扩展的 ,因此它基本上是一个场景图节点,与任何其他JavaFX节点一样,除了您可以使用图形基元(Canvas API)直接在表面上绘制和操纵像素数据( GraphicsContext), )。
要在画布上绘制,必须首先实例化 具有宽度和高度 的 画布 节点。 实例化 Canvas 类后,您将需要获取其 GraphicsContext 对象。 要获取 GraphicsContext, 只需调用其 getGraphicsContext2D() 方法。 该 GraphicsContext 类有方法使开发人员在图形绘制的图元访问许多。 这些绘图基元提供了绘制形状,填充颜色,设置笔触,应用图像,绘制文本等等的方法。 有关 GraphicsContext 类的 详细信息,请参考JavaDoc 。 清单1 演示了在 GraphicsContext 上进行绘制的基础 。
Canvas canvas = new Canvas(300, 300);
final GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());gc.setFill(Color.BLACK);
gc.setFont(Font.getDefault());
gc.fillText("hello world!", 15, 50);gc.setLineWidth(5);
gc.setStroke(Color.PURPLE);gc.strokeOval(10, 60, 30, 30);
gc.strokeOval(60, 60, 30, 30);
gc.strokeRect(30, 100, 40, 40);root.getChildren().add(canvas);
primaryStage.setScene(scene);
primaryStage.show();
创建 Canvas 类 的实例时 ,您将有机会像其他JavaFX节点一样将其放入场景图。 由于 Canvas 是JavaFX Node 类,因此开发人员(API的用户)可以自由地将其像场景图中的其他任何节点一样对待。 这意味着您可以应用效果,变换和动画。 Canvas API的主要优点之一是,您可以在图形上下文(位图表面)上绘制许多东西,这与矢量渲染策略类似。
但是,代替场景图上的许多节点,画布上的所有图形都封装在一个节点中,从而提高了性能。 请记住,减少场景图上的节点对象的数量有助于实现更好的效率,例如图行走。
使用Canvas API的一个缺点是,开发人员必须从头开始绘制东西,并自行处理效率(例如,计算脏区以进行优化)。 这就是为什么 在某些情况下,JavaFX的基于矢量的策略能够在性能上表现出色的原因。 这些性能的提高归功于它能够检测脏区,提供缓存提示并在后台进行其他操作。 一切都归结为您真正想要达到的目标和期望的效果。
如果您涉足HTML5开发,您会注意到JavaFX的Canvas API的设计看起来与HTML5的Canvas API相似(并非巧合)。 我对编程接口没有遵循Java 2D API(我是它的忠实拥护者)感到惊讶。 但是,我很快就克服了。 网络上许多流行HTML5 / JavaScript示例都可以轻松移植到JavaFX Canvas API,因为它们具有相似的命名约定。 ( 注意: 为了使用Canvas API,必须安装JavaFX 2.2或更高版本。)
围绕JavaFX的Canvas API的所有激动,我决定尝试一下。 由于JavaFX的Canvas API具有许多功能,因此,我仅介绍一下电影 Tron Legacy 的未来派风格化时钟,让您快速了解一下 。 时钟的灵感来自 DeviantArt的 一个名为 Burnwell88 的用户 。 该时钟是使用 Rain Meter 桌面主题制作工具开发的。 在结束语中,我将列出与Canvas API相关的许多功能中的一些功能,本文中将不进行讨论。
在进入代码之前,我想向您展示时钟的简单设计,并提供一个类图,描述演示中使用的类。 下面 描绘了组成弧光时钟的零件的模型:
图3描述了组成我们的演示“弧形时钟”的部分,这些部分由以下部分组成:圆弧( ArcPiece ),小时,分钟,秒和子午线(从左到右)。 既然我们已经从视觉上了解了组成弧光时钟的部分,那么让我向您展示一个类图,其中列出了捕获演示需求所需的所有类。 图4 列出了此时钟演示中使用的四个类。
图4的类图的左侧显示了两个主要类,用于使用弧线绘制时钟。 ArcClock 类是容器类型的类,可容纳零到许多 ArcPiece 实例。 一个 ArcClock 也包含时钟的半径和直径(时钟的边界框的宽度)。 单独的弧对象x ArcPiece) 将包含弧属性,稍后将在每个更新和渲染周期将其渲染到画布上。 在图3中 , ArcPieceBuilder 类(右上)是遵循面向对象 构建器模式 的便捷类 。 使用此类提供了一种 在声明性语法样式编程中 构造 ArcPiece 实例 的简便方法 。 这种模式使开发人员能够减少样板代码,并允许指定临时参数(方法链接)。
表1 显示了描述 ArcPiece 类的 所有属性 :
属性 | 数据类型 | 例 | 描述 |
X | 双 | 0 | 边界框的左上x坐标 |
ÿ | 双 | 0 | 边界框的左上y坐标 |
w | 双 | 200 | 时钟周围边框的宽度 |
H | 双 | 200 | 时钟周围边框的高度 |
startAngle | 双 | 45 | 圆弧的起始角度,以度为单位 |
arcExtent | 双 | 240 | 角度范围(度) |
strokeWidth | 双 | 5 | 弧线笔划的像素粗细 |
pixelToMove | 双 | 1个 | 动画弧似乎旋转的像素数 |
strokeColor | 颜色 | 红色 | 笔触的颜色 |
顺时针 | 布尔型 | 真正 | 动画弧以顺时针移动,否则逆时针移动 |
表1:ArcPiece类中包含的属性
为简便起见,我觉得最好将属性 公开 为 公共 属性, 而 不是 实现类似于Java bean规范(约定)的getter和setter方法。 另外,我选择使用简单的原始数据类型而不是JavaFX Properties API。 使用原语可以帮助降低开销(需要绑定多个值)。 在某个时候,您可能希望在更受限的设备(例如 Raspberry Pi , BeagleBoard 等) 上使用嵌入式Java版本运行演示 。
现在您已经知道要绘制和绘制弧线的属性,让我们看一下它的外观。 图5 描述了使用属性x,y,w,h,startAngle,arcExtent,strokeColor和 ArcType绘制的弧 。 对于我们的演示,我将所有弧都硬编码为 ArcType.OPEN 。
图5显示了要在画布上绘制的弧线信息。
下面的清单显示了用于在 GraphicsContext 上绘制圆弧的代码段 。
final GraphicsContext gc = canvas.getGraphicsContext2D();
...
gc.setStroke(strokeColor);
gc.setLineWidth(strokeWidth);
gc.strokeArc(x, // upper left x coord y, // upper left y coordw, // widthh, // heightstartAngle,arcExtent,ArcType.OPEN);
运行我们的演示的主驱动程序或JavaFX Application位于 TronClockDemo 类中( 清单3 )。 该主驱动程序类包含一个 AnimationTimer 实例,该实例将定期更新弧光时钟的属性并将零件绘制到 GraphicsContext 表面上。
下面的清单显示了主要的驱动程序类TronClockDemo.java,并启动了JavaFX应用程序:
/** Driver class to run the demo which extends from* JavaFX's Application class. The demo will make use of* JavaFX's Canvas API. This class creates three clocks* which are animated using an AnimationTimer class.** Inspired by http://burnwell88.deviantart.com/art/Clock-136761577* and http://rainmeter.net/cms/** Created with IntelliJ IDEA.* User: cdea* Date: 10/15/12* Time: 12:20 AM**/
public class TronClockDemo extends Application {public static void main(String[] args) {Application.launch(args);}@Overridepublic void start(final Stage primaryStage) {Group root = new Group();Scene scene = new Scene(root, 650, 220, Color.rgb(0,0,0));// create a canvas nodeCanvas canvas = new Canvas();// bind the dimensions when the user resizes the window.canvas.widthProperty().bind(primaryStage.widthProperty());canvas.heightProperty().bind(primaryStage.heightProperty());// obtain the GraphicsContext (drawing surface)final GraphicsContext gc = canvas.getGraphicsContext2D();// create three clocksfinal ArcClock blueClock = new ArcClock(20, BLUE1, BLUE2, 200);final ArcClock greenClock = new ArcClock(20, BLUE1, GREEN1, 200);final ArcClock redClock = new ArcClock(20, BLUE1, RED1, 200);// create an animation (update & render loop)new AnimationTimer() {@Overridepublic void handle(long now) {// update clocksblueClock.update(now);greenClock.update(now);redClock.update(now);// clear screengc.clearRect(0, 0, primaryStage.getWidth(),primaryStage.getHeight());// draw blue clockblueClock.draw(gc);// save the origin or the current state// of the Graphics Context.gc.save();// shift x coord position the width of a clock plus 20 pixelsgc.translate(blueClock.maxDiameter + 20, 0);greenClock.draw(gc);// shift x coord position past the first clockgc.translate(blueClock.maxDiameter + 20, 0);redClock.draw(gc);// reset Graphics Context to last saved point.// Translate x, y to (0,0)gc.restore();}}.start();// add the single node onto the scene graphroot.getChildren().add(canvas);primaryStage.setScene(scene);primaryStage.show();}}
最初,应用程序的main方法将通过 Application.launch() 方法 启动JavaFX应用程序线程 。 一旦应用程序线程准备就绪(post init() 方法), 就会调用 start() 方法。 要查看其他生命周期方法,请转到JavaDocs on Application 类 。 您会在清单3中注意到,所有操作都发生在 start() 方法中。 在这里 使用匿名内部类创建 AnimationTimer 实例,并使用 AnimationTimer 启动该实例 。 start() 方法。 在每个周期发生时, JavaFX Application线程都会调用 handle() 方法。 调用 handle() 方法时,您会注意到 long 类型 的入站参数“ now ” 是一帧的当前时间(以纳秒为单位)。
handle()方法的主体将采取以下步骤:
更新时钟模型(蓝色时钟,绿色时钟和红色时钟)
清除萤幕
画蓝色时钟
保存GraphicsContext状态
将X坐标平移到蓝色时钟的右侧
画绿色时钟
将X坐标平移到绿色时钟的右侧
画红色时钟
恢复或返回上一个保存的GraphicsContext状态
下面的清单显示了一个简单Java类的源代码,该类负责包含弧的模型。
/** ArcPiece is an object representing the state (model)* of an arc shape that will be drawn on the Graphics Context. During* an animation loop values in the model will often be* updated. The update() method has the ability to calculate* elapsed time to allow the arc to later be animated based on* frames per second. The draw() method simply renders the arc* shape onto the Graphics Context (surface).** Created with IntelliJ IDEA.* User: cdea*/
public class ArcPiece {public double x;public double y;public double w;public double h;public double startAngle;public double arcExtent;public double strokeWidth = 2;public double pixelsToMove = 2;public Color strokeColor;public boolean clockwise=false;long startTime = 0;public long displayTimePerFrameMillis = 60;private long displayTimePerFrameNano = 60 * 1000000;public void update(long now) {if (startTime == 0){startTime = now;displayTimePerFrameNano = displayTimePerFrameMillis * 1000000;}long elapsed = now - startTime;if (elapsed > displayTimePerFrameNano) {if (!clockwise){startAngle = startAngle + pixelsToMove;if (startAngle > 360){startAngle = 0;}} else {startAngle = startAngle - pixelsToMove;if (startAngle < -360){startAngle = 0;}}startTime = 0;}}public void draw(GraphicsContext gc) {gc.setStroke(strokeColor);gc.setLineWidth(strokeWidth);gc.strokeArc(x,y,w,h,startAngle,arcExtent,ArcType.OPEN);}
}
此清单还包含两个方法 update() 和 draw() ,这将有助于动画周期更新值并将弧渲染到绘图表面( GraphicsContext )。
下一个清单显示了 ArcClock.java 文件 的源代码,该 文件是表示时钟模型的容器类。
/** This class is a container class that maintains* all of the parts that comprised of a clock. It is* also responsible for updating and drawing itself* at each animation frame cycle.* The ArcClock contains zero to many ArcPiece objects* to be drawn. The clock will also display the time* of day.** User: cdea*/
public class ArcClock {public static Color BLUE1 = Color.rgb(126, 166, 212, 0.6);public static Color BLUE2 = Color.rgb(126, 166, 222, 0.5);public static Color BLUE3 = Color.rgb(130, 166, 230, 0.5);public static Color GREEN1 = Color.rgb(130, 230, 166, 0.5);public static Color RED1 = Color.rgb(230, 130, 166, 0.5);public ArcPiece longPiece;public ArcPiece[] arcPieces;public int maxDiameter;public double radius;private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddhhmmssa");public ArcClock(int numArcs, Color longPieceColor, Color manyPieceColor, int maxDiameter) {this.maxDiameter = maxDiameter;radius = maxDiameter / 2;longPiece = ArcPieceBuilder.create().strokeColor(longPieceColor).strokeWidth(5).x(0).y(0).w(maxDiameter).h(maxDiameter).startAngle(45).arcExtent(240).displayTimePerFrameMillis(1000).pixelsToMove(1).build();arcPieces = createRandomArcs(numArcs, manyPieceColor, maxDiameter / 2);}public void update(long now){longPiece.update(now);for (ArcPiece ap:arcPieces) {ap.update(now);}}public void draw(GraphicsContext gc) {longPiece.draw(gc);for (ArcPiece ap:arcPieces) {ap.draw(gc);}// draw hourgc.setFont(Font.font("Calibri", 40));gc.setFill(Color.WHITE);gc.setTextAlign(TextAlignment.CENTER);String dateTimeStr = DATE_FORMAT.format(new Date());//yyyyMMddhhmmssagc.fillText(dateTimeStr.substring(8, 10) , radius, radius + 18 );gc.setFont(Font.font("Calibri", 20));gc.fillText(dateTimeStr.substring(10, 12) + " " + dateTimeStr.substring(14) , maxDiameter - 40, radius - 40 );gc.fillText(dateTimeStr.substring(12, 14) , maxDiameter - 40, maxDiameter - 40 );}public static int randomIntRange(int min, int max) {Random rand = new Random();int range = max - min + 1;return rand.nextInt(range) + min;}public static ArcPiece[] createRandomArcs(int num, Color color, double radius) {final ArcPiece[] manyPieces = new ArcPiece[num];for (int i=0; i<num; i++) {manyPieces[i] = randomArcPiece(color, radius);}return manyPieces;}public static ArcPiece randomArcPiece(Color color, double radius) {int width = randomIntRange(60, (int) radius * 2);int randomStrokeWidth = randomIntRange(1,10);int randomStartAngle = randomIntRange(1, 270);int randomExtentAngle = randomIntRange(10, 360-randomStartAngle);long randomMillis = randomIntRange(0, 33);Color someColor = color;if (color == null) {someColor = BLUE1;}final ArcPiece arcPiece = ArcPieceBuilder.create().strokeColor(someColor).strokeWidth(randomStrokeWidth).x(radius - (width/2)).y(radius - (width/2)).w(width).h(width).startAngle(randomStartAngle).arcExtent(randomExtentAngle).displayTimePerFrameMillis(randomMillis).pixelsToMove(2).build();arcPiece.clockwise = new Random().nextBoolean();return arcPiece;}
}
此列表以将在我们的三个演示时钟中使用的预定义颜色开始。 实例变量如下: longPiece , arcPieces , maxDiameter 和 radius 。 表2 描述了 ArcClock 类 的实例的属性 。
属性 | 数据类型 | 例 | 描述 |
长片 | ArcPiece | 在钟的外缘上画出一个单一的圆弧 | |
arcPieces | ArcPiece | 时钟中许多随机绘制的开放弧 | |
最大直径 | 整型 | 200 | 时钟宽度 |
半径 | 双 | 100 | 时钟的一半宽度 |
要创建 ArcClock 的实例 , 构造函数将调用许多静态方法来构建具有变化的起始角度和范围角度的随机开放弧形。 需要指出的另一件事是 update() 和 draw() 方法,这些方法用于辅助动画周期( AnimationTimer )。 在每个动画周期,时钟将更新模型并将圆弧渲染到图形上下文中。 除了为弧形时钟渲染所有弧形片段外, ArcClock 类还将使用 GraphicsContext的 fillText() 方法 显示(绘制)时间 。
好了,您可以快速了解JavaFX Canvas API。 尽管我们仅涉及Canvas API功能的表面,但是我列出了JavaFX 2.2和Canvas API的其他一些有趣功能。
快照 –任何“场景图”节点都可以将节点的图像捕获为位图图像。
PixelWriter –能够修改位图图像上的像素信息。
PixelReader –能够从位图图像读取像素信息。
混合 -在画布上绘制时的混合模式(图形上下文)。
图层 –具有许多提供图层(z顺序)的图形上下文的能力。
编码愉快! 我相信您会更深入地研究这些有趣的功能。
翻译自: https://jaxenter.com/tutorial-a-glimpse-at-javafxs-canvas-api-105696.html
javafx canvas
javafx canvas_教程:JavaFX的Canvas API概览相关推荐
- JavaFX技巧2:使用Canvas API进行清晰绘图
当我最初开始使用Canvas API时,我注意到渲染代码的结果有些模糊,甚至更糟,不一致. 有些线条模糊,有些线条清晰. 来自Swing,我花了一些时间才意识到这是由JavaFX的坐标系引起的,该坐标 ...
- javafx基础教程_JavaFX教程–基础
javafx基础教程 JavaFX似乎正在RIA领域获得发展. 有了正确的工具和开发支持,它肯定会成为下一个最佳技术"物"的代价. 我没有在这里写任何JavaFX评论,因为有很多技 ...
- javafx canvas_JavaFX技巧2:使用Canvas API进行清晰绘图
javafx canvas 最初开始使用Canvas API时,我注意到渲染代码的结果有些模糊,甚至更糟,不一致. 有些线条模糊,有些线条清晰. 来自Swing,我花了一些时间才意识到这是由JavaF ...
- JavaFX官方教程(一)之JavaFX概述
翻译自 JavaFX概述 本章概述了可以使用JavaFX API构建的应用程序类型,下载JavaFX库的位置以及有关正在交付的关键JavaFX功能的高级信息. JavaFX是一组图形和媒体包,使开发 ...
- 易百教程——JavaFX教程
转载自 易百教程--JavaFX教程 JavaFX是Java的下一代图形用户界面工具包.JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序. JavaFX允许开发人员快速 ...
- JavaFX官方教程(七)之使用FXML创建用户界面
翻译自 使用FXML创建用户界面 本教程展示了使用JavaFX FXML的好处,JavaFX FXML是一种基于XML的语言,它提供了构建与代码的应用程序逻辑分开的用户界面的结构. 如果您从一开始就 ...
- JavaFX 8 教程 (中文)
http://code.makery.ch/library/javafx-8-tutorial/zh-cn/ 早在 2012 我和我的学生们写了一个非常详细的 JavaFX 2 系列教程.世界各 ...
- JavaFX官方教程(十三)之应用效果
翻译自 Applying Effects 创建视觉效果包含以下主题: 混合效果 绽放效果 模糊效果 投影效果 内阴影效果 反射 照明效果 透视效果 创建一系列效果 介绍如何使用视觉效果来增强Java ...
- JavaFX官方教程(四)之Hello World,JavaFX样式
翻译自 Hello World,JavaFX Style 教你创建和构建JavaFX应用程序的最佳方法是使用"Hello World"应用程序.本教程的另一个好处是,它使您能够 ...
- Android基础入门教程——8.3.18 Canvas API详解(Part 3)Matrix和drawBitmapMash
Android基础入门教程--8.3.18 Canvas API详解(Part 3)Matrix和drawBitmapMash 标签(空格分隔): Android基础入门教程 本节引言: 在Canva ...
最新文章
- 国产光刻机正式宣布:今年出货150台
- Cloud Native概念
- windows 2008+Oracle 11g R2 故障转移群集配置
- GMIS 2017大会Saman Farid演讲:人工智能时代创业者面对的挑战和机会
- 反思技术面试题目准备汇总链接汇总
- 一个单片机的小问题。
- ZOJ 3747 Attack on Titans
- C++如何调用父类的方法?
- sql计算留存_SQL基础第七讲:关于用户留存率的计算
- 光模块是怎么分类的?光模块的应用及作用有哪些?
- Suse发生了错误Access denied for user #39;#39;@#39;localhost#39; toamp;
- 手动触发事件_HBase中MemStore的刷写触发机制
- 默认情况下linux主机在机房托管期间被,托管机房作业未传之秘
- BZOJ2199[Usaco2011 Jan] 奶牛议会
- JavaWeb学习笔记——Mac os下在idea中创建Web项目以及部署Tomcat
- php获取所有微信号,PHP 微信公众号开发 - 获取用户信息
- 利用gitlab pages和hexo搭建一个个人博客
- 淘宝的返利网怎么用_淘宝便宜的方法
- “生死看淡”的雷军要造车,这对中国的汽车产业意味着什么?
- 【C++】公积金贷款计算器
热门文章
- 范德蒙行列式、克拉默法则、雅可比矩阵
- 机器人关节伺服电机PID串级控制
- suitecrm 如何backup and restore ,从一个server 转移到另一个 server . 并保证customer package , customer module 不丢...
- 服务器CRT显示不全,CRT显示器显示画面不正常常见原因揭密
- dnf全部使用_DNF的命令使用教学
- Android简易本地音乐播放器,Android简易音乐播放器实现代码
- html 多选框取值,多选框取值
- Vue 富文本编辑器
- 涉密计算机用户密码操作规程,涉密计算机管理设置密码
- 彻底清理c盘空间,本人亲测有效--WinDirStat