- 浏览: 180330 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
Brooke:
啥时候分享一下源码呗 学习一下
基于eclipse RCP的文件夹管理工具 -
红耳飞鹏:
貌似懂了之后才能看的懂,个人看法
刷新 javaFX2.0 数据视图(TableView/ListView/TreeView) -
leaow567:
这个要支持啊
基于eclipse RCP的文件夹管理工具--FileTools -
yunchow:
luoyu-ds 写道我是来看博主的头像的+1
eclipse RCP 模仿win7资源管理器地址栏功能 -
luoyu-ds:
我是来看博主的头像的
eclipse RCP 模仿win7资源管理器地址栏功能
译自: http://java.dzone.com/articles/javafx-numbertextfield-and
作者: Thomas Bolz
我最近花了一些时间学习javaFX, 要更深入地理解新GUI包, 自定义控制器可能是一个比较好的方法. 由于我是开发财务软件的, 所以我当然希望javaFX中也有类似JFormattedTextField和JSpinner的控件. 这对我来说确实是个不错的选择.
这是我的控制器:
- 数字文本框(NumberTextField): 可以配置任意格式的数字;
- 微调控制器( NumberSpinner ): 可以使用键盘方向键或箭头按钮来控制数值;它也是控制器的一部分;
控制器及其示例可以在这里下载(可直接导入到netbeans,见附件). 示例中还包含一个css样式文件, 它用于控制Spinner的风格是直角或圆角.
NumberTextField
NumberTextField 的实现很容易,以致我认为这算不上自定义控制器, 而仅仅是改变一个已存在的控制器的一些行为而已. NumberTextField 扩展自JFX中的文本框(TextField), 添加一个使用BigDecimal(由于财务软件需要精确的类型)的NumberProperty作为模型, 并做一些格式化和解析处理. 就这样, 不复杂.
package de.thomasbolz.javafx; import java.math.BigDecimal; import java.text.NumberFormat; import java.text.ParseException; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.TextField; /** * Textfield implementation that accepts formatted number and stores them in a * BigDecimal property The user input is formatted when the focus is lost or the * user hits RETURN. * * @author Thomas Bolz */ public class NumberTextField extends TextField { private final NumberFormat nf; private ObjectProperty<BigDecimal> number = new SimpleObjectProperty<>(); public final BigDecimal getNumber() { return number.get(); } public final void setNumber(BigDecimal value) { number.set(value); } public ObjectProperty<BigDecimal> numberProperty() { return number; } public NumberTextField() { this(BigDecimal.ZERO); } public NumberTextField(BigDecimal value) { this(value, NumberFormat.getInstance()); } public NumberTextField(BigDecimal value, NumberFormat nf) { super(); this.nf = nf; initHandlers(); setNumber(value); } private void initHandlers() { // try to parse when focus is lost or RETURN is hit setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent arg0) { parseAndFormatInput(); } }); focusedProperty().addListener(new ChangeListener<Boolean>() { @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { if (!newValue.booleanValue()) { parseAndFormatInput(); } } }); // Set text in field if BigDecimal property is changed from outside. numberProperty().addListener(new ChangeListener<BigDecimal>() { @Override public void changed(ObservableValue<? extends BigDecimal> obserable, BigDecimal oldValue, BigDecimal newValue) { setText(nf.format(newValue)); } }); } /** * Tries to parse the user input to a number according to the provided * NumberFormat */ private void parseAndFormatInput() { try { String input = getText(); if (input == null || input.length() == 0) { return; } Number parsedNumber = nf.parse(input); BigDecimal newValue = new BigDecimal(parsedNumber.toString()); setNumber(newValue); selectAll(); } catch (ParseException ex) { // If parsing fails keep old number setText(nf.format(number.get())); } } }
NumberSpinner
NumberSpinner好像复杂一点. 它构建在NumberTextField 上, 并使用递增和递减按钮来改变文本框中数字的值, 每次改变步长为stepwidth.
stepwidth和NumberFormat的初始值在构造器中指定. 文本框和按钮的大小取决于文本的大小. 文本的大小可在.css文件中设置.
package de.thomasbolz.javafx; import java.math.BigDecimal; import java.text.NumberFormat; import javafx.beans.binding.NumberBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.shape.LineTo; import javafx.scene.shape.MoveTo; import javafx.scene.shape.Path; import javax.swing.JSpinner; /** * JavaFX Control that behaves like a {@link JSpinner} known in Swing. The * number in the textfield can be incremented or decremented by a configurable * stepWidth using the arrow buttons in the control or the up and down arrow * keys. * * @author Thomas Bolz */ public class NumberSpinner extends HBox { public static final String ARROW = "NumberSpinnerArrow"; public static final String NUMBER_FIELD = "NumberField"; public static final String NUMBER_SPINNER = "NumberSpinner"; public static final String SPINNER_BUTTON_UP = "SpinnerButtonUp"; public static final String SPINNER_BUTTON_DOWN = "SpinnerButtonDown"; private final String BUTTONS_BOX = "ButtonsBox"; private NumberTextField numberField; private ObjectProperty<BigDecimal> stepWitdhProperty = new SimpleObjectProperty<>(); private final double ARROW_SIZE = 4; private final Button incrementButton; private final Button decrementButton; private final NumberBinding buttonHeight; private final NumberBinding spacing; public NumberSpinner() { this(BigDecimal.ZERO, BigDecimal.ONE); } public NumberSpinner(BigDecimal value, BigDecimal stepWidth) { this(value, stepWidth, NumberFormat.getInstance()); } public NumberSpinner(BigDecimal value, BigDecimal stepWidth, NumberFormat nf) { super(); this.setId(NUMBER_SPINNER); this.stepWitdhProperty.set(stepWidth); // TextField numberField = new NumberTextField(value, nf); numberField.setId(NUMBER_FIELD); // Enable arrow keys for dec/inc numberField.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent keyEvent) { if (keyEvent.getCode() == KeyCode.DOWN) { decrement(); keyEvent.consume(); } if (keyEvent.getCode() == KeyCode.UP) { increment(); keyEvent.consume(); } } }); // Painting the up and down arrows Path arrowUp = new Path(); arrowUp.setId(ARROW); arrowUp.getElements().addAll(new MoveTo(-ARROW_SIZE, 0), new LineTo(ARROW_SIZE, 0), new LineTo(0, -ARROW_SIZE), new LineTo(-ARROW_SIZE, 0)); // mouse clicks should be forwarded to the underlying button arrowUp.setMouseTransparent(true); Path arrowDown = new Path(); arrowDown.setId(ARROW); arrowDown.getElements().addAll(new MoveTo(-ARROW_SIZE, 0), new LineTo(ARROW_SIZE, 0), new LineTo(0, ARROW_SIZE), new LineTo(-ARROW_SIZE, 0)); arrowDown.setMouseTransparent(true); // the spinner buttons scale with the textfield size // TODO: the following approach leads to the desired result, but it is // not fully understood why and obviously it is not quite elegant buttonHeight = numberField.heightProperty().subtract(3).divide(2); // give unused space in the buttons VBox to the incrementBUtton spacing = numberField.heightProperty().subtract(2).subtract(buttonHeight.multiply(2)); // inc/dec buttons VBox buttons = new VBox(); buttons.setId(BUTTONS_BOX); incrementButton = new Button(); incrementButton.setId(SPINNER_BUTTON_UP); incrementButton.prefWidthProperty().bind(numberField.heightProperty()); incrementButton.minWidthProperty().bind(numberField.heightProperty()); incrementButton.maxHeightProperty().bind(buttonHeight.add(spacing)); incrementButton.prefHeightProperty().bind(buttonHeight.add(spacing)); incrementButton.minHeightProperty().bind(buttonHeight.add(spacing)); incrementButton.setFocusTraversable(false); incrementButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent ae) { increment(); ae.consume(); } }); // Paint arrow path on button using a StackPane StackPane incPane = new StackPane(); incPane.getChildren().addAll(incrementButton, arrowUp); incPane.setAlignment(Pos.CENTER); decrementButton = new Button(); decrementButton.setId(SPINNER_BUTTON_DOWN); decrementButton.prefWidthProperty().bind(numberField.heightProperty()); decrementButton.minWidthProperty().bind(numberField.heightProperty()); decrementButton.maxHeightProperty().bind(buttonHeight); decrementButton.prefHeightProperty().bind(buttonHeight); decrementButton.minHeightProperty().bind(buttonHeight); decrementButton.setFocusTraversable(false); decrementButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent ae) { decrement(); ae.consume(); } }); StackPane decPane = new StackPane(); decPane.getChildren().addAll(decrementButton, arrowDown); decPane.setAlignment(Pos.CENTER); buttons.getChildren().addAll(incPane, decPane); this.getChildren().addAll(numberField, buttons); } /** * increment number value by stepWidth */ private void increment() { BigDecimal value = numberField.getNumber(); value = value.add(stepWitdhProperty.get()); numberField.setNumber(value); } /** * decrement number value by stepWidth */ private void decrement() { BigDecimal value = numberField.getNumber(); value = value.subtract(stepWitdhProperty.get()); numberField.setNumber(value); } public final void setNumber(BigDecimal value) { numberField.setNumber(value); } public ObjectProperty<BigDecimal> numberProperty() { return numberField.numberProperty(); } public final BigDecimal getNumber() { return numberField.getNumber(); } // debugging layout bounds public void dumpSizes() { System.out.println("numberField (layout)=" + numberField.getLayoutBounds()); System.out.println("buttonInc (layout)=" + incrementButton.getLayoutBounds()); System.out.println("buttonDec (layout)=" + decrementButton.getLayoutBounds()); System.out.println("binding=" + buttonHeight.toString()); System.out.println("spacing=" + spacing.toString()); } }
number_spinner.css
最后, 控制器的样式可在css文件中设置. 我实现了圆角和直角两种风格(见上文截图). 你可以通过修改 #NumberField, #ButtonBox, #SpinnerButtonUp 和#SpinnerButtonDown 中的border/background-radiuses来切换不同的风格.
.root{ -fx-font-size: 24pt; /* -fx-base: rgb(255,0,0);*/ /* -fx-background: rgb(50,50,50);*/ } #NumberField { -fx-border-width: 1; -fx-border-color: lightgray; -fx-background-insets:1; -fx-border-radius:3 0 0 3; /* -fx-border-radius:0 0 0 0;*/ } #NumberSpinnerArrow { -fx-fill: gray; -fx-stroke: gray; /* -fx-effect: innershadow( gaussian , black , 2 , 0.6 , 1 , 1 )*/ } #ButtonsBox { -fx-border-color:lightgray; -fx-border-width: 1 1 1 0; -fx-border-radius: 0 3 3 0; /* -fx-border-radius: 0 0 0 0;*/ } #SpinnerButtonUp { -fx-background-insets: 0; -fx-background-radius:0 3 0 0; /* -fx-background-radius:0;*/ } #SpinnerButtonDown { -fx-background-insets: 0; -fx-background-radius:0 0 3 0; /* -fx-background-radius:0;*/ }
结论
从上面的例子可以看出在javaFx中自定义控制器并不困难. JavaFX自2.0版本以后作为一个纯粹的java API, 其比以前的任何版本更好地整合诸如groovy(BigDecimal的乐土)的语言. 这将是财务桌面应用的黄金组合.
- JavaFXSpinner_1.zip (24.5 KB)
- 下载次数: 51
发表评论
-
eclipse RCP 模仿win7资源管理器地址栏功能
2013-04-23 15:25 2928本文实现效果及其工具下载地址:http://sourcef ... -
[EasyTao(道)系列文章之一]太极之道
2012-07-22 10:05 1417综述 周易是中国传统文化的基石. 涵盖了包括哲学在内的 ... -
基于eclipse RCP的文件夹管理工具
2012-07-14 00:45 3281总的来说, Windows7的文件夹浏览器已经提供了很好 ... -
基于eclipse RCP的文件夹管理工具
2012-07-13 23:36 4闲来无事, 做个文件夹浏览器玩玩----基于eclipse R ... -
基于eclipse RCP的文件夹管理工具
2012-07-13 23:34 3闲来无事, 做个文件夹浏览器玩玩 -
基于eclipse RCP的文件夹管理工具
2012-07-13 23:34 3闲来无事, 做个文件夹浏览器玩玩 -
javafx2.0 初体验之 处方管理系统
2012-02-16 00:15 2692总体感觉 JFX2 应用起来比swing方便;其效果类似于f ... -
javafx2.0 修改控件默认鼠标键盘监听
2012-02-04 10:57 6569JFX为所有空间提供了默认的鼠标键盘监听,以符合一般使用 ... -
javafx2.0 在表格(TableView)中显示选择按钮(CheckBox)
2012-02-03 22:23 10597要在JFX的表格中显示自定义的单元(TableCe ... -
刷新 javaFX2.0 数据视图(TableView/ListView/TreeView)
2012-02-02 20:49 8674数据视图(TableView/ListView/T ... -
javafx2.0 获取TableView 正在编辑的单元TableCell
2012-02-02 19:52 7957JFX使用CellFactory(Callback)来获取每个 ... -
javafx2.0 资源
2012-02-02 13:27 1904教程: 官方教程. 下载地址:http:/ ... -
JavaFX的2.0常见问题合集
2012-02-02 13:19 2338JavaFX的2.0常见问题 1。 在JavaFX ... -
javafx2.0 监听树和表的选择变化
2012-01-13 22:47 6060Swing中的组件都有对应的选择模型(SelectionMod ... -
开源地图编辑器 mepper
2011-09-30 17:09 3017Mepper 这是我在2009年参与的项目中开 ... -
[转]AOP在大规模软件开发项目中应用的尝试与思考
2011-08-08 12:31 1483珉 李 (minli@cn ... -
单例模式和软引用[Soft Singleton Idiom]
2011-05-22 15:35 1725原文出自:http://www.javaworld.com/c ... -
【草稿 勿看】伟大的重构
2011-04-08 00:18 69一句话:进行大规模重构时,不要一下子就删掉原来的东西。先把新的 ... -
Java7异常新特性之mutilcatch
2011-03-25 14:36 2128历经4年,Java7终于和大家见面。关于Java7的新特性, ...
相关推荐
Javafx 2.0: Introduction by Example
JavaFX实战:模拟电子琴弹奏效果音效资源
Use the JavaFX platform to create rich-client Java applications and discover how you can use this powerful Java-based UI platform, which is capable of handling large-scale data-driven business ...
《Netty+JavaFx实战:仿桌面版微信聊天》| 本项目是作-chat.itstack.github.io
使用JavaFX开发关于2010世界杯的C-S应用(NetBeans项目)
JavaFx2:创建一个表单
JavaFX 官方教程:RIA 应用开发
In Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology, Jim Weaver, Weiqi Gao, Stephen Chin, Dean Iverson, and Johan Vos show you how you can use the JavaFX platform to create rich-...
实现对文本框的匹配,比如已存在的匹配集合包含:“abc”、"aa"、"bb" 输入a时就会匹配到"abc"和"aa
Javafx1:测试阶段需要大量升级
JavaFX 2.0 Introduction by Example.zip是javafx2.0的最新书籍《[JavaFX.2.0:Introduction.by.Example].Carl.Dea》上的源码!大家可以下载本书和源码一起看!我都上传了!
资源名称:JavaFX 官方教程:RIA 应用开发内容简介:《JavaFX官方教程:RIA应用开发》通过使用JavaFX,开发人员和平面设计师可以协同工作来构建健壮的、拟真的应用程序,并能够将它部署到任何地方:桌面、Web、数...
资源名称:JAVA FX官方教程:RIA应用开发内容简介:《JavaFX官方教程:RIA应用开发》通过使用JavaFX,开发人员和平面设计师可以协同工作来构建健壮的、拟真的应用程序,并能够将它部署到任何地方:桌面、Web、数百万...
In Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology, Jim Weaver, Weiqi Gao, Stephen Chin, Dean Iverson, and Johan Vos show you how you can use the JavaFX platform to create rich-...
JavaFX高级教程:JavaFX2.0的FXML语言.docx 官方中文文档
Chapter 2, Building Blocks – Shapes, Text, and Controls, fills the window we created in the previous chapter with various building blocks provided by the JavaFX API. Chapter 3, Connecting Pieces – ...
书-javafx2 从javafx2书籍中收集的示例汇编就像它读的一样,我找到了一本精妙的javafx2书籍,以加深我对该Java框架的理解,顺便说一句。
JavaFX高级教程:部署JavaFX2.0应用 官方中午文档
JavaFX+官方教程:RIA+应用开发