列表
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 { @Override 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>>() { @Override 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>() { @Override public void handle(ActionEvent event) { String text = field.getText(); list.add(new Student(text)); } }); b2.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { // 选择当前选择的行 int i = listView.getSelectionModel().getSelectedIndex(); if (i >= 0){ list.remove(i); } } }); b3.setOnAction(new EventHandler<ActionEvent>() { @Override 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>{ @Override 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{ @Override public void start(Stage primaryStage) throws Exception { BorderPane root = new BorderPane(); Button b1 = new Button("点我"); b1.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override 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 { @Override 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>(); @Override 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() { @Override 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; } @Override 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>>() { @Override public ListCell<FileItem> call(ListView<FileItem> param) { return new MyListCell(); } }); } // 获取数据源 public ObservableList<FileItem> data() { return listData; } // 设置单元格显示 static class MyListCell extends ListCell<FileItem> { @Override 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(); } @Override 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(); @Override 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); } } @Override 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() { @Override 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; } @Override 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(); @Override 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>() { @Override 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); }