前几天,在公司的项目中做了个小工具,就想起用一下JavaFx来了,貌似JavaFx不是很火啊,网上的资料还真不多,在开发过程中遇到了一些问题,下面和大家分享一下。
JavaFx学习起来不难,很快就能上手,效果也很好,但是JavaFx中没有表格,这个令我很郁闷,上网发现了一个E文的博客,里面有我想到的东西,感兴趣的可以去看看:http://blogs.sun.com/rakeshmenonp/entry/javafx_database_table
表格是用长方形一个一个拼上去的,不过效果挺好,我改了一下他的代码,增加了一些功能:
效果图:
主类,表格主体:
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.Group;
import javafx.scene.layout.Panel;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.ClipView;
import javafx.scene.layout.Resizable;
import javafx.scene.input.KeyCode;
import javafx.util.Math;
import javafx.util.Sequences;
import javafx.scene.control.CheckBox;
import cn.com.jit.auth.ums.deletetool.info.User;
/**
* @author Rakesh Menon
* @改造 helly2115
*/
public class CustomerTable extends CustomNode, Resizable {
//列名
public var columnName : String[] = [ "姓名", "ID", "性别", "地址" ];
//列宽度
public var columnWidth : Number[] = [ 50, 180, 120, 40 ];
//行高度
public def rowHeight = 20.0;
//是否包含复选框
public var comboBox:Boolean = false;
//是否包含序号
public var index:Boolean = false;
def columnCount = bind sizeof columnName;
//当前选择的行
public var selectedIndex = -1 on replace {
if((columnCount > 0) and (selectedIndex >= 0)) {
setSelectedIndex(selectedIndex);
}
}
//当前选择的列
var columnIndex = -1;
//这里是一个只读变量,用户存储用户信息,这里使用了程序在其他定义的javabean做为数据类型,也可以给这个table单独做一个javabean
public-read var customerList : User[] = [];
//复选框存储变量,所有的复选框
public-read var checkBoxList : CheckBox[] = [];
//全选复选框
var HeadCheckBox:CheckBox;
def panel : Panel = Panel {
layoutX: 1
layoutY: 1
onLayout: onLayout
}
def panelClipView = ClipView {
node: panel
width: bind background.width
height: bind background.height
clipX: bind hScroll.value
clipY: bind vScroll.value
pannable: false
}
def background : Rectangle = Rectangle {
width: bind width
height: bind height
fill: Color.DARKGRAY
}
//纵向滚动条
def vScroll:ScrollBar = ScrollBar {
vertical: true
layoutX: bind background.width
height: bind height
max: bind Math.max(panel.boundsInLocal.height - background.height, 1)
}
//横向滚动条
def hScroll:ScrollBar = ScrollBar {
vertical: false
layoutY: bind background.height
width: bind width
max: bind Math.max(panel.boundsInLocal.width - background.width, 1)
}
//创建组件,是覆盖CustomNode中的抽象方法,自己写组件时必须用到的。
override function create() : Node {
//插入复选框
if(comboBox){
insert '' before columnName[0];
insert 20 before columnWidth[0];
}
//插入序号
if(index){
insert '序号' before columnName[0];
insert 40 before columnWidth[0];
}
//创建列头
addHeader();
Group {
content: [
background, panelClipView, hScroll, vScroll
]
};
}
function onLayout() : Void {
var col = 0;
var row = 0;
var colX = 0.0;
for(cell in panel.content) {
cell.layoutX = colX;
cell.layoutY = (rowHeight + 1) * row;
(cell as Cell).width = columnWidth[col];
(cell as Cell).height = rowHeight;
colX += columnWidth[col] + 1;
col++;
if(col >= columnCount) {
col = 0;
colX = 0;
row++;
}
}
}
//鼠标按下事件,主要是计算当前行和当前列
override var onMousePressed = function(e) {
requestFocus();
if(e.source.parent.parent instanceof Cell) {
var cell = (e.source.parent.parent) as Cell;
var index = Sequences.indexOf(panel.content, cell)/columnCount;
if(index >= 0) {
selectedIndex = index - 1;
}
var cindex = Sequences.indexOf(panel.content, cell) mod columnCount;
if(cindex >= 0) {
columnIndex = cindex;
}
}
}
//鼠标点击事件,触发复选框的点击
override var onMouseClicked = function(e) {
if(columnIndex==1 and sizeof customerList>0){
if(selectedIndex==-1){
var flag = HeadCheckBox.selected;
//全选
for(checkBox in checkBoxList){
if(flag){
checkBox.selected = false;
HeadCheckBox.selected = false;
}else{
checkBox.selected = true;
HeadCheckBox.selected = true;
}
}
}else{
var cb:CheckBox = checkBoxList[selectedIndex];
if(cb.selected){
cb.selected = false;
}else{
cb.selected = true;
}
}
}
}
//鼠标滚轮事件
override var onMouseWheelMoved = function(e){
if(e.wheelRotation>0){
var index = selectedIndex + 1;
if(index < ((sizeof (panel.content)/columnCount) - 1)) {
selectedIndex = index;
}
}else{
var index = selectedIndex - 1;
if(index >= 0) {
selectedIndex = index;
}
}
var total:Number = (sizeof (panel.content)/columnCount)- 1;
var now:Number = selectedIndex+1;
var max:Number = vScroll.max;
if(total!=0){
if(selectedIndex==0){
vScroll.value = 0;
}else{
vScroll.value = max*now/total;
}
}
}
//键盘事件,上下可以移动表格
override var onKeyPressed = function(e) {
if(e.code == KeyCode.VK_UP) {
var index = selectedIndex - 1;
if(index >= 0) {
selectedIndex = index;
}
} else if(e.code == KeyCode.VK_DOWN) {
var index = selectedIndex + 1;
if(index < ((sizeof (panel.content)/columnCount) - 1)) {
selectedIndex = index;
}
}
}
//设置被选中的
function setSelectedIndex(index : Integer) : Void {
for(node in panel.content) {
(node as Cell).selected = false;
}
var arrayIndex = (index + 1) * columnCount;
for(i in [arrayIndex..(arrayIndex + columnCount - 1)]) {
(panel.content[i] as Cell).selected = true;
}
}
//添加列头
function addHeader() {
for(header in columnName) {
if(header==''){
HeadCheckBox = CheckBox{};
insert HeaderCell {
graphic:HeadCheckBox
} into panel.content
}else{
insert HeaderCell {
text: "{header}"
} into panel.content;
}
}
}
//增加行
public function addRow(customer : User) : Void {
//序号
if(index){
insert Cell { text: "{(sizeof customerList)+1}" } into panel.content;
}
//复选框
if(comboBox){
var cb = CheckBox{};
insert cb into checkBoxList;
insert Cell { graphic:cb } into panel.content;
}
//插入行中每一个元素
insert Cell { text: "{customer.getName()}" } into panel.content;
insert Cell { text: "{customer.getIdcardnum()}" } into panel.content;
insert Cell { text: "{customer.getOrgpath()}" } into panel.content;
insert Cell { text: "{customer.getX509subject()}" } into panel.content;
insert customer into customerList;
}
//清空表格
public function clear() : Void {
delete customerList;
delete panel.content;
delete checkBoxList;
selectedIndex = -1;
addHeader();
}
//删除行
public function deleteRow(index : Integer) : Void {
if(index < 0) {
return;
}
var startIndex = (columnCount * (index + 1));
for(i in [startIndex..(startIndex + columnCount - 1)]) {
delete panel.content[startIndex];
}
delete customerList[index];
if(index == selectedIndex) {
selectedIndex = -1;
}
}
//获取高度,覆盖Resizable中的方法
override function getPrefHeight(w: Number) {
if(height <= 0) {
return 300;
}
return height;
}
//获取宽度,覆盖Resizable中的方法
override function getPrefWidth(h: Number) {
if(width <= 0) {
return 300;
}
return width;
}
}
列头类:
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
/**
* @author Rakesh Menon
*/
public class HeaderCell extends Cell {
override var fill = Color.rgb(93, 93, 93);
override var textFill = Color.LIGHTGRAY;
override var font = Font.font("sansserif", FontWeight.BOLD, 12);
}
行类:
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.control.Label;
import javafx.scene.Group;
import javafx.scene.layout.Resizable;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
/**
*
* @author Rakesh Menon
*/
def margin = 3;
public class Cell extends CustomNode, Resizable {
public var text : String;
public var graphic: Node;
public var selected = false;
public var fill: Paint = Color.WHITE;
public var selectedFill: Paint = Color.rgb(0, 147, 255);
public var textFill: Paint = Color.BLACK;
public var selectedTextFill: Paint = Color.WHITE;
public var font: Font = Font.font("sansserif", FontWeight.REGULAR, 12);
def background = Rectangle {
fill: bind if(selected) selectedFill else fill
width: bind width
height: bind height
}
def label = Label {
layoutX: margin
layoutY: margin
text: bind "{text}"
graphic: bind graphic
width: bind width - (margin * 2)
font: bind font
textFill: bind if(selected) selectedTextFill else textFill
}
override function create() : Node {
Group {
content: [
background, label
]
}
}
override function getPrefHeight(width: Number) {
label.getPrefHeight(width);
}
override function getPrefWidth(height: Number) {
label.getPrefWidth(height);
}
}