今天这个文章 比上两篇就稍微难了点,emm 代码也比之前多了点。
列表
ListView 列表
TreeView 树列表
TableView 表格
TreeTableView 多列多表
代码分析:
首先就是使用了 hbox 作为top部分的 文件行 和 三个按钮
每个按钮对应一个监听器 监听不同的处理动作
整体使用了布局嵌套 使用了student泛型 把内容显示在列表里
列表里需要自定义单元格 最终把字符显示在单元格里
package sample;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import javafx.util.Callback;
public class DemoList extends Application {
public void start(Stage primaryStage) throws Exception {
// 添加hbox
HBox hBox = new HBox();
TextField field = new TextField();
Button b1 = new Button("添加");
Button b2 = new Button("删除");
Button b3 = new Button("修改");
hBox.getChildren().addAll(field,b1,b2,b3);
// 设置listview
ListView<Student> listView = new ListView<>();
// 设置数据源
ObservableList<Student> list = FXCollections.observableArrayList();
// 设置数据源
listView.setItems(list);
// 生成单元格
listView.setCellFactory(new Callback<ListView<Student>, ListCell<Student>>() {
public ListCell<Student> call(ListView<Student> param) {
return new mycell();
}
});
// 添加数据
list.add(new Student("张三"));
list.add(new Student("王五"));
list.add(new Student("李丹"));
BorderPane root = new BorderPane();
HBox.setHgrow(field, Priority.ALWAYS);
// 添加按钮监听
b1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
String text = field.getText();
list.add(new Student(text));
}
});
b2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
// 选择当前选择的行
int i = listView.getSelectionModel().getSelectedIndex();
if (i >= 0){
list.remove(i);
}
}
});
b3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
int i = listView.getSelectionModel().getSelectedIndex();
String name = field.getText();
if (i > 0){
// 获取索引对应的数字
Student s = list.get(i);
// 覆盖数据
s.name = name;
list.set(i,s);
}
}
});
root.setTop(hBox);
root.setCenter(listView);
primaryStage.setTitle("列表属性");
primaryStage.setScene(new Scene(root,400,300));
primaryStage.show();
}
// 单元格显示
static class mycell extends ListCell<Student>{
protected void updateItem(Student item, boolean empty) {
super.updateItem(item, empty);
if (item != null){
this.setText(item.name);
} else if(empty || item == null){
setText(null);
}
}
}
static class Student{
private String name;
public Student(){}
public Student( String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
效果图如下
鼠标事件处理
鼠标可以常用的监听方式
左键单击
左键双击
右键单击
在MouseEvent 对象里,能得到以下信息:
event.getButton() 按钮 (左,中,右)
event.getClickCount() 移动0 单击1 双击2
event.getX() 点击位置 窗口坐标
event.getSceneX() 单击位置 屏幕坐标
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class demo1 extends Application{
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
Button b1 = new Button("点我");
b1.setOnMouseClicked(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
// 对鼠标点击的事件进行处理
if ( event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2){
System.out.println("鼠标左键点击了两次");
} else if(event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 1){
System.out.println("鼠标左键点击了一次");
}
/**
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("弹窗标题");
alert.setHeaderText("弹窗信息");
alert.showAndWait();
*/
}
});
root.setCenter(b1);
primaryStage.setTitle("鼠标操作");
primaryStage.setScene(new Scene(root,500,50));
primaryStage.show();
}
}
树列表
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class DemoTreeView extends Application {
public void start(Stage primaryStage) throws Exception{
StackPane root = new StackPane();
TreeItem treeItem = new TreeItem<>("根目录");
treeItem.setExpanded(true);
for(int i = 0;i < 5;i++){
TreeItem item = new TreeItem<>("节点:" + i);
treeItem.getChildren().add(item);
}
TreeView treeView = new TreeView<>(treeItem);
root.getChildren().add(treeView);
primaryStage.setTitle("TreeView的使用");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
}
代码分析:
使用treeview 展示树列表 多层嵌套TreeItem 就是多层树列表
多列表
顾名思义 就是树列表 多排几列 如下图: 名词对应的列 修改时间 类型 大小等
import java.io.File;
public class UploadItem{
public long localId; // 本地上传分配的ID
public String localGUID; // 本地上传分配的GUID
public String thumb;
public File filePath; // 本地文件路径
public String title; // 标题, 默认为文件名, 但允许被用户改名
public long size; // 文件大小
public long timeCreated;
public UploadItem(){}
public UploadItem(String title, long size, long timeCreated){
this.title = title;
this.size = size;
this.timeCreated = timeCreated;
}
}
package sample.duoTree;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.BorderPane;
public class Main extends Application{
TreeTableView<UploadItem> treeTable = new TreeTableView<UploadItem>();
public void start(Stage primaryStage){
initTreeTable();
initTreeData();
BorderPane root = new BorderPane();
root.setCenter(treeTable);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private void initTreeTable()
{
// 添加多个列
TreeTableColumn<UploadItem, UploadItem> columns[] = new TreeTableColumn[3];
columns[0] = new TreeTableColumn("文件名");
columns[1] = new TreeTableColumn("大小");
columns[2] = new TreeTableColumn("任务创建时间");
treeTable.getColumns().addAll(columns);
// 定义每个列的列宽
columns[0].setPrefWidth(150);
columns[1].setPrefWidth(80);
columns[2].setPrefWidth(120);
// 设置 CellValueFactory (此段写法固定)
Callback cellValueFactory = new Callback() {
public Object call(Object param){
CellDataFeatures p = (CellDataFeatures)param;
return p.getValue().valueProperty();
}
};
for(int i=0; i<columns.length; i++){
columns[i].setCellValueFactory(cellValueFactory);
}
// 设置CellFactory,定义每一列的单元格的显示
// 这里使用了lambda表达式,否则写起来太长了!
columns[0].setCellFactory((param)->{
return new MyTableTreeCell("title");
});
columns[1].setCellFactory((param)->{
return new MyTableTreeCell("size");
});
columns[2].setCellFactory((param)->{
return new MyTableTreeCell("filePath");
});
}
private void initTreeData(){
// 根节点只是占一个位置
TreeItem<UploadItem> root = new TreeItem<UploadItem>(new UploadItem());
treeTable.setRoot( root );
treeTable.setShowRoot(false);
UploadItem data_1 = new UploadItem("测试视频", 192000, System.currentTimeMillis());
root.getChildren().add( new TreeItem( data_1));
UploadItem data_2 = new UploadItem("测试图片", 239000, System.currentTimeMillis());
root.getChildren().add( new TreeItem( data_2));
}
// 单元格的显示
class MyTableTreeCell extends TreeTableCell<UploadItem,UploadItem>{
String columnID;
public MyTableTreeCell(String columnID){
this.columnID = columnID;
}
protected void updateItem(UploadItem item, boolean empty){
super.updateItem(item, empty);
// 自定义单元格显示内容
if (empty || item == null){
setText(null);
setGraphic(null);
} else{
setGraphic(null);
if(columnID.equals("title"))
this.setText(String.valueOf(item.title));
else if(columnID.equals("size"))
this.setText(String.valueOf(item.size));
else if(columnID.equals("filePath"))
this.setText(String.valueOf(item.timeCreated));
}
}
}
}
案例 文件查看器
思路:
程序支持查看java代码 txt文件 图片。
左侧显示文件名 右侧显示其内容
package sample.readUtils;
import java.io.File;
public class FileItem {
public String fileName; // 文件名
public String firstName; // 前缀名
public File file;
public int type = BAD_FORMAT; // 1, 文本文件; 2,图片文件; -1, 不支持的文件类型
// 文件类型常量
public static final int TEXT = 1;
public static final int IMAGE = 2;
public static final int BAD_FORMAT = -1;
// 后缀数组
private final String[] txtTypes = { "txt", "java"};
private final String[] imageTypes = { "jpg", "jpeg", "png", "bmp" };
// 构造函数,传入一个file并取得file的名字和类型
public FileItem(File file) {
this.file = file;
// 取得文件名
fileName = file.getName();
firstName = getFileFirstName(fileName);
// 根据文件后缀来判断文件的类型
String suffix = getFileSuffix(fileName);
type = BAD_FORMAT;
if (contains(txtTypes, suffix))
type = TEXT;
else if (contains(imageTypes, suffix))
type = IMAGE;
}
// 判断是否图片
public boolean contains(String[] types, String suffix) {
suffix = suffix.toLowerCase(); // 统一转成小写
for (String s : types) {
if (s.equals(suffix))
return true;
}
return false;
}
// 获取文件名的后缀
public String getFileSuffix(String name) {
int pos = name.lastIndexOf('.');
if (pos > 0)
return name.substring(pos + 1);
return ""; // 无后缀文件
}
// 获取文件名前缀
public String getFileFirstName(String name) {
int pos = name.lastIndexOf('.');
if(pos > 0) {
return name.substring(0, pos);
}
return "";
}
}
package sample.readUtils;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ListCell;
/*
* 左侧的文件列表
*/
import javafx.scene.control.ListView;
import javafx.util.Callback;
public class FileListView extends ListView<FileItem> {
private ObservableList<FileItem> listData = FXCollections.observableArrayList();
// 构造函数
public FileListView() {
setItems(listData);
// 设置单元格生成器 (工厂)
setCellFactory(new Callback<ListView<FileItem>, ListCell<FileItem>>() {
public ListCell<FileItem> call(ListView<FileItem> param)
{
return new MyListCell();
}
});
}
// 获取数据源
public ObservableList<FileItem> data() {
return listData;
}
// 设置单元格显示
static class MyListCell extends ListCell<FileItem> {
protected void updateItem(FileItem item, boolean empty) {
// FX框架要求必须先调用 super.updateItem()
super.updateItem(item, empty);
// 自己的代码
if (item == null) {
this.setText("");
} else {
this.setText(item.fileName);
}
}
}
}
package sample.readUtils;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
/*
* 用于显示图片的工具类
* 封装成一个容器
* 这个容器显示整张图片
* 适应父窗口
*/
public class MyImagePane extends Pane {
ImageView imageView = new ImageView();
Image image;
public MyImagePane() {
// 添加图片
getChildren().add(imageView);
}
public void showImage(Image image) {
this.image = image;
imageView.setImage(image);
layout();
}
protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
// 对ImageView进行摆放,使其适应父窗口
imageView.resizeRelocate(0, 0, w, h);
imageView.setFitWidth(w);
imageView.setFitHeight(h);
imageView.setPreserveRatio(true);
}
}
package sample.readUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class TextFileUtils {
public static String read(File f, String charset) throws Exception{
FileInputStream fstream = new FileInputStream(f);
try {
int fileSize = (int)f.length();
if(fileSize > 1024*512)
throw new Exception("File too large to read! size=" + fileSize);
byte[] buffer = new byte[fileSize];
// 读取到字符数组里
fstream.read(buffer);
return new String(buffer, charset);
}finally {
try{
fstream.close();
}catch(Exception e) {}
}
}
public static void write(File f, String text, String charset) throws Exception
{
FileOutputStream fstream = new FileOutputStream(f);
try{
fstream.write( text.getBytes( charset ));
}finally
{
fstream.close();
}
}
}
package sample.readUtils;
import java.io.File;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
FileListView fileList = new FileListView();
TabPane tabPane = new TabPane();
public void start(Stage primaryStage) {
// 加载左侧文件列表
initFileList();
BorderPane root = new BorderPane();
root.setLeft(fileList);
root.setCenter(tabPane);
Scene scene = new Scene(root,800,500);
primaryStage.setTitle("文件浏览器");
primaryStage.setScene(scene);
primaryStage.show();
}
public void initFileList(){
fileList.setPrefWidth(200);
// 左侧加载小仙女目录下的文件
File dir = new File("C:\Users\Administrator\Desktop\demo");
File[] files = dir.listFiles();
for(File f : files) {
FileItem fitem = new FileItem(f);
// 添加到左侧列表中
fileList.data().add(fitem);
}
// 列表是鼠标事件响应
fileList.setOnMouseClicked((MouseEvent event)->{
// 如果左键单击的话
if(event.getClickCount() == 1 && event.getButton() == MouseButton.PRIMARY) {
oneClicked();
}
});
}
// 单击处理
public void oneClicked() {
// 获取列表选中模块,获取索引
int index = fileList.getSelectionModel().getSelectedIndex();
FileItem fitem = fileList.data().get(index);
try {
openFile(fitem);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 打开左侧文件
public void openFile(FileItem fitem) throws Exception{
// 查看选项卡是否打开
Tab tab = findTab(fitem);
if(tab != null) {
// 设置为选中的选项卡
// int pos = tabPane.getTabs().indexOf(tab); // 获取id
tabPane.getSelectionModel().select(tab);
return;
}
// 打开一个新的选项卡并选中
Node currentView = null;
if(fitem.type == FileItem.TEXT) {
// 文本文件处理
String str = TextFileUtils.read(fitem.file, "UTF-8");
TextArea t = new TextArea();
t.setText(str);
currentView = t;
}else if(fitem.type == FileItem.IMAGE) {
// 图片文件处理
// 获取文件的本地路径
Image image = new Image(fitem.file.toURI().toString());
MyImagePane t = new MyImagePane();
t.showImage(image);
currentView = t;
}else throw new Exception("不支持打开该格式");
// 创建新的选项卡并选中
tab = new Tab();
tab.setText(fitem.firstName);
tab.setContent(currentView);
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
}
// 查看在右侧选项卡是否打开
public Tab findTab(FileItem fitem) {
ObservableList<Tab> tabs = tabPane.getTabs();
for(Tab tab : tabs) {
if(tab.getText().equals(fitem.firstName)) {
return tab;
}
}
return null;
}
public static void main(String[] args) {
launch(args);
}
}
案例 目录浏览器
打开一个目录 显示内文件名 大小 修改时间
package sample.file;
import java.io.File;
public class FileInfo {
public File file;
public String name; // 文件名
public long lastModified; // 最后修改时间
public long size; // 文件大小
public boolean isDir = false; // 判断目录
public FileInfo() {
}
public FileInfo(File f) {
// 获取文件的一些属性
this.file = f;
name = f.getName();
size = f.length();
lastModified = f.lastModified();
isDir = f.isDirectory();
}
}
package sample.file;
import java.text.SimpleDateFormat;
import java.util.List;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;
import javafx.util.Callback;
public class FileBrowser extends TreeTableView<FileInfo> {
// 根节点
TreeItem rootItem = new TreeItem(new FileInfo());
// 列
TreeTableColumn<FileInfo, FileInfo> columns[] = new TreeTableColumn[3];
public FileBrowser() {
// 初始化列的设置
initColumns();
// 扁平化显示, 不显示根节点, 但必须要有根节点
this.setRoot( rootItem );
this.setShowRoot(false);
}
// 清空
public void clear() {
rootItem.getChildren().clear();
}
// 添加
public void add(List<FileInfo> datalist) {
for(FileInfo fi : datalist) {
TreeItem item = new TreeItem(fi);
rootItem.getChildren().add(item);
}
}
protected void layoutChildren() {
super.layoutChildren();
// 动态设置列宽
double w = this.getWidth();
double w0 = w * 0.4;
double w1 = w * 0.2;
double w2 = w - w0 - w1- 20;
columns[0].setPrefWidth(w0);
columns[1].setPrefWidth(w1);
columns[2].setPrefWidth(w2);
}
private void initColumns() {
// 添加多个列
columns[0] = new TreeTableColumn("文件名");
columns[1] = new TreeTableColumn("大小");
columns[2] = new TreeTableColumn("最后修改时间");
this.getColumns().addAll(columns);
// 重写layoutChildren() 动态调整个列的列宽
// 设置 CellValueFactory (此段写法固定)
Callback cellValueFactory = new Callback() {
public Object call(Object param) {
CellDataFeatures p = (CellDataFeatures)param;
return p.getValue().valueProperty();
}
};
for(int i=0; i<columns.length; i++) {
columns[i].setCellValueFactory(cellValueFactory);
}
// 设置CellFactory,定义每一列的单元格的显示
// 这里使用了lambda表达式,否则写起来太长了!
columns[0].setCellFactory((param)->{
return new MyTreeTableCell("name");
});
columns[1].setCellFactory((param)->{
return new MyTreeTableCell("size");
});
columns[2].setCellFactory((param)->{
return new MyTreeTableCell("lastModified");
});
}
// 单元格的显示
static class MyTreeTableCell extends TreeTableCell<FileInfo,FileInfo> {
static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String columnID;
public MyTreeTableCell(String columnID) {
this.columnID = columnID;
}
protected void updateItem(FileInfo item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setGraphic(null);
if(columnID.equals("name")) {
this.setText(String.valueOf(item.name));
}
else if(columnID.equals("size")) {
if(item.isDir) // 如果是目录则不显示大小
setText("目录");
else
setText(String.valueOf(item.size));
}
else if(columnID.equals("lastModified")) {
this.setText(sdf.format(item.lastModified)); // 格式化为年月日时分秒
}
}
}
}
}
package sample.file;
import java.io.File;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
Stage stage; // 主窗口
// 文件浏览功能
FileBrowser fileBrowser = new FileBrowser();
public void start(Stage primaryStage) {
this.stage = primaryStage;
// 面板
BorderPane root = new BorderPane();
root.setCenter(fileBrowser);
primaryStage.setTitle("目录练习");
primaryStage.setScene( new Scene(root, 600, 400));
primaryStage.show();
// 按钮添加
Button btnOpen = new Button("打开目录");
root.setTop(btnOpen);
btnOpen.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
// 当我点击按钮 打开窗口
openFolder();
}
});
}
// 打开目录
private void openFolder() {
// 选择一个目录
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle("打开目录");
// 展示目录
File dir = chooser.showDialog(stage);
// dir是用户选中的目录
if (dir != null) {
showFiles(dir);
}
}
// 显示目录下的文件
private void showFiles(File dir) {
File[] files = dir.listFiles();
if(files == null || files.length == 0){
return;
}
ArrayList<FileInfo> datalist = new ArrayList<FileInfo>();
for(File f : files) {
datalist.add(new FileInfo( f));
}
// 显示这些文件/目录的列表
fileBrowser.clear();
fileBrowser.add( datalist );
}
public static void main(String[] args) {
launch(args);
}
}
原文始发于微信公众号(轩公子谈技术):javaFx 安全开发 三
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论