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

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

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

bildschirmfoto-2015-06-15-um-19-25-50

最重要的类称为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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VirtualBox命令更改虚拟硬盘空间

主要是使用VBoxManage命令来操作第一步&#xff1a;打开CMD&#xff0c;进入到virtualbox存放虚拟机的目录中(win7 系统可以直接在文件夹空白处按住shift键右键鼠标选择[在此处打开命令窗口])&#xff0c;输入[vboxmanage list hdds]可以查看所有的虚拟机的信息&#xff0c;这里…

华为手机老是android自动升级,华为手机系统怎么升级 华为手机升级系统的两种方法...

华为手机使用的均为安卓系统&#xff0c;升级方法有多种&#xff0c;各位可以根据条件不同自行选择升级。华为手机升级系统的两种方法方法一&#xff1a;手机联网更新首先把手机联网。点击设置。向下拖动点击最后一项“关于手机”点击“系统软件更新”。点击在线升级即可。友情…

linux网络体系架构

原创kylin_zeng:http://blog.csdn.net/kylin_fire_zeng 本文参考国嵌视频教程&#xff0c;再此感谢国嵌教育。 一、协议栈层次对比&#xff1a; 1&#xff09;网络接口层把数据链路层和物理层合并在了一起&#xff0c;提供访问物理设备的驱动程序&#xff0c;对应的网络协议主…

android 自定义弹窗diss,Android中自定义PopupWindow,动态弹窗。

我的第一篇博客&#xff0c;咱们直奔主题。先上个效果图在android中自定义PopupWindow&#xff1a;1、首先定义好你想要显示的窗口的布局文件&#xff0c;再实例化一个View对象&#xff1a;窗口布局可灵活变化&#xff0c;dialog_layout.xml代码如下&#xff1a;android:id&quo…

拼图项目的动机和目标

几周前&#xff0c;我写了一篇关于Jigsaw项目如何破坏现有代码的文章 。 那么&#xff0c;我们能得到什么回报呢&#xff1f; 让我们看一下项目解决的痛点及其在Java 9中解决问题的目标。 系列 这篇文章是正在进行的有关拼图项目系列的一部分。 按照推荐的顺序&#xff08;不同…

android中按一个按钮弹出字,允许用户在Android中长按一次即可编辑按钮文字

我想允许App用户在Android中更改Button文本。 当用户单击按钮时&#xff0c;它应该执行某些操作&#xff0c;但是当他/她长按按钮时&#xff0c;将弹出一个编辑文本&#xff0c;并且无论用户键入什么内容都应另存为按钮文本。到目前为止&#xff0c;我已经完成了以下操作。btn1…

关于单元测试脚手架的几点思考

莱昂&#xff1a;Luc Besson的专业人士 当我开始通过创建相同的对象并准备数据来运行测试来重复使用单元测试方法时&#xff0c;我对设计感到失望。 带有大量代码重复的长时间测试方法看起来并不正确。 为了简化和缩短它们&#xff0c;基本上有两个选项&#xff0c;至少在Java…

android 使用c 代码实现,JNI开发实现helloworld,调用自己的C代码实现(1)

JNI开发&#xff0c;实现自己的C代码&#xff0c;helloworld在这里实现一个简单的demo,完成加载自己的C代码使用Android studio&#xff0c;一步一步教你实现在屏幕上显示出helloworld如下图显示&#xff0c;配置号NDK的路径&#xff0c;没有路径的需要自己下载&#xff0c;在A…

使用WSO2 ESB进行邮件内容过滤

每个集成架构师或开发人员都应该熟悉Gregor Hohpe和Bobby Woolf所描述的企业集成模式&#xff08;EIP&#xff09; 。 模式之一是“内容消息过滤器” &#xff08;不要与消息过滤器模式混淆&#xff09;。 使用不同的Mediator在WSO2中有多种方法可以实现此目的。 一种方法是使…

android壁纸应用,HPSTR - 可能是你见过最会玩的壁纸应用 - Android 应用 - 【最美应用】...

今天这款 HPSTR 壁纸应用也不例外&#xff0c;HPSTR 主要的壁纸素材源来自 Unsplash(ios/android)、500px(android)、Reddit(android)这些素材源的图片都很优秀&#xff0c;特别是 Unsplash 它是著名的无版权图片网站。它家主要以风景为主&#xff0c;数量也足够多&#xff0c;…

android sqlite批量操作,Android: SQLite批量插入数据的最佳实践

大家都知道&#xff0c;Android里数据库用的是SQLite。在实际开发过程中&#xff0c;我们有时候会遇到批量插入数据的场景。这篇文章给大家分享一个小技巧&#xff0c;让批量插入数据达到最快的目的。首先&#xff0c;我先创建一个Table&#xff0c;里面只有一个字段&#xff1…

c语言实现linux下的top命令来获取cpu利用率_有用的一篇笔记,linux 调优各项监控指标...

自开始负责生产环境部署&#xff0c;中间遇到了若干线上环境内存以及CPU的问题。由于微服务以及容器的流行&#xff0c;现在已经可以很方便的使用 K8s prometheus grafana alert 的方式进行监控&#xff0c;这足以覆盖大部分场景。最重要的事情已经交由最适合的组件去做&…

rip协议中周期性广播路由信息的报文_技术实操||距离矢量路由协议-RIP

距离矢量路由协议—RIP01距离矢量路由协议概述路由信息协议RIP(RoutingInformation Protocol)的简称&#xff0c;它是一种基于距离矢量(Distance-Vector)算法的协议&#xff0c;使用跳数作为度量来衡量到达目的网络的距离。RIP主要应用于规模较小的网络中。RIP是一种比较简单的…

使用tinylog 1.0简化您的日志记录

tinylog的大小仅为75 KB&#xff0c;是广泛使用的经典日志记录框架Log4j和Logback的轻型替代方案。 经过三年的开发&#xff0c;最终版本1.0刚刚于 3月底发布 。 在几个设计问题中&#xff0c;tinylog采取了与Java中经典日志记录框架完全不同的方法。 本文将介绍与Log4j和Logba…

华谊兄弟出现什么问题_什么是语言训练?这就要从语言问题的出现说起了

开口、发音是每一个孩子在语言发展过程中所不可少的经历&#xff0c;他们从周围环境中获取到的各种信息转化为想要表达的内容。虽然一开始孩子的语言并没有成年人那么流畅和准确&#xff0c;但随着时间的推移&#xff0c;他们的说话发音愈发成熟。只是&#xff0c;并不是所有孩…

【算法提升—力扣每日一刷】五日总结【12/18--12/22】

文章目录 2023/12/18LeetCode每日一刷&#xff1a;[20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) 2023/12/19LeetCode每日一刷&#xff1a;[150. 逆波兰表达式求值&#xff08;后缀表达式运算&#xff09;](https://leetcode.cn/problems/evaluate-rever…

CompletableFuture不能被打断

我已经写了很多有关InterruptedException和中断线程的文章 。 简而言之&#xff0c;如果您没有Future.cancel()调用Future.cancel()那么Future将终止待处理的get() &#xff0c;但还将尝试中断基础线程。 这是一个非常重要的功能&#xff0c;可以更好地利用线程池。 我还写信总…

crio电压采集 labview_NI cDAQ917采集温度方法

NI cDAQ-9171是一款由总线供电的单槽NI CompactDAQ USB机箱&#xff0c;适合较小的便携式传感器测量系统。cDAQ-9171可与50多款专用测量模块配合使用&#xff0c;用于构建模拟输出、数字I/O或计数器/定时器测量系统。这些模块适用于各种传感器测量&#xff0c;包括热电偶、RTD、…

android finish 区别,Android Activity类finish、onDestory和System.exit介绍

image.pngfinish函数Activity.finish()Call this when your activity is done and should be closed.在你的activity动作完成的时候&#xff0c;或者Activity需要关闭的时候&#xff0c;调用此方法。当调用此方法的时候&#xff0c;系统只是将最上面的Activity移出了栈&#xf…

在JVM中记录世界停顿

不同的事件可能导致JVM暂停所有应用程序线程。 这种暂停称为世界停止&#xff08;STW&#xff09;暂停。 触发STW暂停的最常见原因是垃圾回收&#xff08; 例如github中的示例 &#xff09;&#xff0c;但是不同的JIT操作&#xff08; 示例 &#xff09;&#xff0c;偏向锁吊销…