JavaFX应用程序似乎有两种:第一种使用带有节点和CSS样式的场景图,第二种使用单个画布。 但是,将这两种方法混合使用是完全合法的。 尤其是当您的应用程序必须显示大量详细信息时,您很容易最终创建成千上万个节点。 即使JavaFX的整体性能非常出色,当所有这些节点都需要样式设置时(特别是由于可视化的动态性质而需要反复进行样式设置时),您很有可能会使系统崩溃。

对我来说,这是一个顿悟,当我意识到在FlexGanttFX中保证高性能的唯一方法是对每个包含画布的单元使用ListView。 不幸的是,该框架的代码太复杂,无法在一个小博客中与您共享。因此,我写了一个小例子来说明基本概念。 下图显示了运行示例时的结果。 ListView显示的数据涵盖了我生命中的岁月,并且每年的每一天都有随机生成的值。

最重要的类称为CanvasCell 。 它是一个专门的列表视图单元,其中包含标签和画布。 标签用于显示年份,画布用于绘制图表。

import java.util.Collections;
import java.util.List;import javafx.geometry.Pos;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;public class CanvasCell extends ListCell<YearEntry> {private Label yearLabel;private ResizableCanvas canvas;public CanvasCell() {/** Important, otherwise we will keep seeing a horizontal scrollbar.*/setStyle("-fx-padding: 0px;");yearLabel = new Label();yearLabel.setStyle("-fx-padding: 10px; -fx-font-size: 1.2em; -fx-font-weight: bold;");StackPane.setAlignment(yearLabel, Pos.TOP_LEFT);/** Create a resizable canvas and bind its width and height to the width* and height of the table cell.*/canvas = new ResizableCanvas();canvas.widthProperty().bind(widthProperty());canvas.heightProperty().bind(heightProperty());StackPane pane = new StackPane();pane.getChildren().addAll(yearLabel, canvas);setGraphic(pane);setContentDisplay(ContentDisplay.GRAPHIC_ONLY);}@Overrideprotected void updateItem(YearEntry entry, boolean empty) {if (empty || entry == null) {yearLabel.setText("");canvas.setData(Collections.emptyList());canvas.draw();} else {yearLabel.setText(Integer.toString(entry.getYear()));canvas.setData(entry.getValues());canvas.draw();}}/** Canvas is normally not resizable but by overriding isResizable() and* binding its width and height to the width and height of the cell it will* automatically resize.*/class ResizableCanvas extends Canvas {private List<Double> data = Collections.emptyList();public ResizableCanvas() {/** Make sure the canvas draws its content again when its size* changes.*/widthProperty().addListener(it -> draw());heightProperty().addListener(it -> draw());}@Overridepublic boolean isResizable() {return true;}@Overridepublic double prefWidth(double height) {return getWidth();}@Overridepublic double prefHeight(double width) {return getHeight();}public void setData(List<Double> data) {this.data = data;}/** Draw a chart based on the data provided by the model.*/private void draw() {GraphicsContext gc = getGraphicsContext2D();gc.clearRect(0, 0, getWidth(), getHeight());Stop[] stops = new Stop[] { new Stop(0, Color.SKYBLUE),new Stop(1, Color.SKYBLUE.darker().darker()) };LinearGradient gradient = new LinearGradient(0, 0, 0, 300, false,CycleMethod.NO_CYCLE, stops);gc.setFill(gradient);double availableHeight = getHeight() * .8;double counter = 0;for (Double value : data) {double x = getWidth() / 365 * counter;double barHeight = availableHeight * value / 100;double barWidth = getWidth() / 365 + 1;gc.fillRect(x, getHeight() - barHeight, barWidth, barHeight);counter++;}}}
}

对于数据,我们使用一个非常简单的类来存储年份和值列表。

import java.util.ArrayList;
import java.util.List;/*** Just some fake model object.*/
public class YearEntry {private int year;public YearEntry(int year) {this.year = year;}public int getYear() {return year;}private List<Double> values = new ArrayList<>();/*** Stores the values shown in the chart.*/public List<Double> getValues() {return values;}
}

以下清单显示了主类。

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;public class CanvasApp extends Application {@Overridepublic void start(Stage stage) throws Exception {/** Create some random data for my life span.*/ObservableList<YearEntry> data = FXCollections.observableArrayList();for (int year = 1969; year < 2015; year++) {YearEntry entry = new YearEntry(year);for (int day = 0; day < 365; day++) {entry.getValues().add(Math.random() * 100);}data.add(entry);}ListView<YearEntry> listView = new ListView<>(data);listView.setCellFactory(param -> new CanvasCell());listView.setFixedCellSize(200);Scene scene = new Scene(listView);stage.setTitle("Canvas Cell");stage.setScene(scene);stage.setWidth(600);stage.setHeight(600);stage.show();}public static void main(String[] args) {launch(args);}
}

翻译自: https://www.javacodegeeks.com/2015/06/javafx-tip-20-a-lot-to-show-use-canvas.html

JavaFX技巧20:有很多需要展示的地方吗? 使用画布!相关推荐

  1. JavaFX技巧来节省内存! 属性和可观察物的阴影场

    在 JavaFX的世界中, Properties API允许UI开发人员将值绑定到UI控件. 这种功能非常容易,但是当对象模型经常使用属性时,应用程序可能会很快耗尽内存. 我通常会编写两个单独的对象, ...

  2. 《树莓派实战秘籍》——1.20 技巧20使用Swap添加额外的内存

    本节书摘来异步社区<树莓派实战秘籍>一书中的第1章,第1.20节,作者:[美]Ruth Suehle ,Tom Callaway,更多章节内容可以访问云栖社区"异步社区" ...

  3. pyecharts交互式动态可视化案例_全国各省近20年GDP 动态展示

    全国各省近20年GDP 动态展示 1. 数据描述: 数据存在EXCEL,命名为全国各省财政收入 2. 编写代码: import pandas as pd import openpyxl from py ...

  4. 超20城急推购房补贴 地方救市力度接近2008年

    超20城急推购房补贴 地方救市力度接近2008年 宏观经济华夏时报[微博]董映颉2014-10-25 00:50 我要分享 608 华夏时报记者 董映颉 北京报道 10月21日,国家统计局发布前三季度 ...

  5. 天正暖通天圆地方在哪_2020位于太白山景区海拔3511米天圆地方景点就变成了很多人望而却步的地方_天圆地方-评论-去哪儿攻略...

    来之前听驴子说过,登太白山绝对是一段极具挑战性的旅程,不仅是海拔高度的攀升,长线的距离也是考验人意志力的时候.位于太白山景区海拔3511米天圆地方景点就变成了很多人望而却步的地方. 不过我们赶时间缆车 ...

  6. javafx显示image_JavaFX技巧20:有很多要显示的吗? 使用画布!

    javafx显示image JavaFX应用程序似乎有两种:第一种使用带有节点和CSS样式的场景图,第二种使用单个画布. 但是,将这两种方法混合使用是完全合法的. 尤其是当您的应用程序必须显示大量详细 ...

  7. JavaFX技巧2:使用Canvas API进行清晰绘图

    当我最初开始使用Canvas API时,我注意到渲染代码的结果有些模糊,甚至更糟,不一致. 有些线条模糊,有些线条清晰. 来自Swing,我花了一些时间才意识到这是由JavaFX的坐标系引起的,该坐标 ...

  8. 职业生涯发展技巧20则

    现将本人整理的职业生涯发展技巧与大家分享,尤其适合踏入工作岗位不久的朋友! 本人是新手上路,觉得好的话顶一下啦! 点击浏览该文件    1.在职业生涯发展的道路上,重要的不是你现在所处的位置,而是迈出 ...

  9. JavaFX技巧32:需要图标吗? 使用Ikonli!

    动机 自2013年以来,我一直在编写JavaFX应用程序和库的代码,它们的共同点是,我需要找到可以用于它们的良好图标/图形. 作为前Swing开发人员,我首先使用图像文件,GIF或PNG. 通常,我会 ...

最新文章

  1. 实战:vue项目中导入swiper插件
  2. 新型智能头盔可快速评估患者中风的大小、位置和类型
  3. 重构了一波代码,聊聊后端也聊聊游戏后端
  4. MATLAB垂直搜索图片中的白段
  5. 简单查找,如果找到返回下标,如果找不到返回-1
  6. boost::leaf::result用法的测试程序
  7. 12 - Runtime实用的几个API
  8. haproxy透传用户ip-方法和原理
  9. Qt中的模态对话框和非模态对话框
  10. Git操作常用的命令都在这里了
  11. 【渝粤教育】国家开放大学2018年春季 3781-22T燃气燃烧技术与设备 参考试题
  12. 第二十一期:拜托!面试不要再问我Spring Cloud底层原理
  13. 华为户外模式怎么设置_华为FreeLace Pro降噪器效果怎么样?降噪开启和设置教程!...
  14. linux远程桌面MacOS,如何在Linux或macOS中使用远程桌面连接到Windows 10 | MOS86
  15. python怎么设置回文数_Python中的回文数
  16. 图解卷积计算原理与pytorch中fold和unfold函数的使用
  17. 9针串口RS232、RS485之间的差异
  18. android手机双开微信方法,微信双开太简单了!学会这几种方法,就能同时登录2个微信...
  19. 简约黑板擦特效表白网源码 附带wap自适应
  20. 计算机科学技术的想象作文600,关于科学的想象作文

热门文章

  1. 使用Servlet上传多张图片——实体层(ProductInfo.java)
  2. Json字符串和对象相互转换
  3. 用idea添加一个模块
  4. MyBatisPlus(笔记)
  5. c语言模拟题答案及解析,全国计算机等考二级C语言模拟试题,答案及解析一
  6. JavaScript 变量的作用域和生命周期
  7. Spring boot(十二):Spring boot 如何测试、打包、部署
  8. 自动配置jdk_JDK 15中自动自动发送更好的NullPointerException消息
  9. ui自动化测试测试报告_您需要了解的有关UI测试的所有信息
  10. 骆驼(camel)命名法_Apache Camel 3 –骆驼核心vs骆驼核心引擎(较小的核心)