javafx tableview中checkbox的全选/反选

第一次写文章,质量请海涵!
最近有被要求做一个简单的javafx桌面应用程序,需要检索目录下的文件,勾选进行文件处理。

这里用到了tableview,可以看到表格的两列check state和File Name都是string类的,点击某列之后check state会改为选定/非选定,同时将选中行的File Name存入list,代码如下:

public class HelloWorld extends Application {
	@FXML
	private final TableView<FileSearch> table = new TableView<>();
	@FXML
	private final ObservableList<FileSearch> data = FXCollections.observableArrayList();
	
	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage primaryStage) {
		GridPane grid = new GridPane();		
		Button btSelect = new Button("全選択");
		btSelect.setId("btSelect");
		grid.add(btSelect, 0, 1);

		final VBox vbox = new VBox();
		vbox.getChildren().addAll(table);
		grid.add(vbox, 0, 2);

		TableColumn firstNameCol = new TableColumn("checkState");
		//checkState以及下面的lastName都是和FileSearch中的属性对应的!
		//这句的完全写法应该是 TableColumn<FileSearch,String> firstNameCol = new TableColumn<FileSearch,String>("checkState"); 这样看起来好多了。
		firstNameCol.setCellValueFactory(new PropertyValueFactory<>("checkState"));
		
		TableColumn<FileSearch,String> lastNameCol = new TableColumn<FileSearch,String>("File Name");
		lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
		table.getColumns().addAll(firstNameCol, lastNameCol);
		
		//表格绑定的点击事件
		//changeList存放选中行的文件名
		List<String> changeList = new ArrayList<>();
		table.setRowFactory(tv -> {
			TableRow<FileSearch> row = new TableRow<>();
			row.setOnMouseClicked(event -> {
				if(!row.isEmpty()) {
					//取到当前选定行的文件名
					String rowData = row.getItem().lastName.getValue();
					//下面的rowData是我对路径格式进行的处理,可忽略
					String[] list = rowData.split("\\\\" );
					rowData = '"' + list[list.length-1].split("\\.")[0] + '"';
					if (row.getItem().getCheckState()== "disSelected") {
						data.get(row.getIndex()).setCheckState("selected");
						//必须刷新一下表,否则值改变了但是表中不动态显示
						table.refresh();
						changeList.add(rowData);
					}else {
					//再次点击从changeList移除选定文件
						row.getItem().setCheckState("disSelected");
						table.refresh();
						remove(changeList, rowData);
					}
				}
			});
			
			//全选/反选按钮点击事件
			btSelect.setOnMouseClicked(event -> {
				if(btSelect.getText() == "全選択") {
					btSelect.setText("全選択解除");
				}else {
					btSelect.setText("全選択");
				}
				table.getItems().forEach(e ->{
					if (e.getCheckState()== "disSelected") {
						e.setCheckState("selected");
						table.refresh();
						changeList.add(e.lastName.getValue());
					}else {
						e.setCheckState("disSelected");
						table.refresh();
						remove(changeList, e.lastName.getValue());
					}
				});
			});
			return row;
		});
		
		primaryStage.setResizable(false);// 窗体缩放(默认为true)
		primaryStage.setScene(scene);
		primaryStage.show();
	}

	public static class FileSearch {
//		private SimpleBooleanProperty box = new SimpleBooleanProperty();
		private SimpleStringProperty checkState = new SimpleStringProperty();
		private SimpleStringProperty lastName = new SimpleStringProperty();
		
		private FileSearch(Boolean cBox, String lName) {
			this.checkState = new SimpleStringProperty(fName);
//			this.box = new SimpleBooleanProperty(cBox);
			this.lastName = new SimpleStringProperty(lName);
		}

		public String getCheckState() {
			return checkState.get();
		}

		public void setCheckState(String fName) {
			checkState.set(fName);
		}
		
//		public Boolean getBox() {
//			return box.get();
//		}

//		public void setBox(Boolean cBox) {
//			box.set(cBox);
//		}

		public String getLastName() {
			return lastName.get();
		}

		public void setLastName(String lName) {
			lastName.set(lName);
		}
	}
}

看起来是完成了我要的需求,但是,故事还没结束。。。。。。
这个check state太出戏了,怎么可能不用checkBox呢?!
其实我一开始是打算直接checkBox的,但是tableview里放插件真的好不舒服,一点没有js那种随便定位到目标元素然后操作的感觉。我们拿check state开刀,加了一句

	firstNameCol.setCellFactory(CheckBoxTableCell.forTableColumn(firstNameCol));

这行代码非常直接地给我的表格第一列画上了漂亮的checkBox(还是自动居中的):
在这里插入图片描述
然后我凉了,花了一天也搞不定这个checkBox的定位,按道理来说应该是非常简单的,毕竟table的点击事件确定第几行后直接给checkBox设定true和false即可,但是现在我怎么点也没反应。搞不定,注掉它!

可能你已经注意到了FileSearch中注释部分,那正是我接下来要干的事情。
我们干掉checkState,加一个Boolean类的Box。

public static class FileSearch {

		private SimpleBooleanProperty box = new SimpleBooleanProperty();
//		private SimpleStringProperty checkState = new SimpleStringProperty();
		private SimpleStringProperty lastName = new SimpleStringProperty();
		
		private FileSearch(Boolean cBox, String lName) {
//			this.checkState = new SimpleStringProperty(fName);
			this.box = new SimpleBooleanProperty(cBox);
			this.lastName = new SimpleStringProperty(lName);
		}

//		public String getCheckState() {
//			return checkState.get();
//		}
//
//		public void setCheckState(String fName) {
//			checkState.set(fName);
//		}
		
		public Boolean getBox() {
			return box.get();
		}

		public void setBox(Boolean cBox) {
			box.set(cBox);
		}

		public String getLastName() {
			return lastName.get();
		}

		public void setLastName(String lName) {
			lastName.set(lName);
		}
	}

对应的firstNameCol也换成box

Callback<TableColumn<FileSearch, Boolean>, TableCell<FileSearch, Boolean>> booleanCellFactory = 
	            new Callback<TableColumn<FileSearch, Boolean>, TableCell<FileSearch, Boolean>>() {
	            @Override
	                public TableCell<FileSearch, Boolean> call(TableColumn<FileSearch, Boolean> p) {
	                    return new BooleanCell();
	            }
	        };
	        firstNameCol.setCellValueFactory(new PropertyValueFactory<FileSearch,Boolean>("box"));
	        firstNameCol.setCellFactory(booleanCellFactory);
class BooleanCell extends TableCell<FileSearch, Boolean> {
        private CheckBox checkBox;
        public BooleanCell() {
            checkBox = new CheckBox();
            checkBox.setDisable(true);
            checkBox.selectedProperty().addListener(new ChangeListener<Boolean> () {
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                    if(isEditing())
                        commitEdit(newValue == null ? false : newValue);
                }
            });
            this.setGraphic(checkBox);
            this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            this.setEditable(true);
        }
        @Override
        public void startEdit() {
            super.startEdit();
            if (isEmpty()) {
                return;
            }
            checkBox.setDisable(false);
            checkBox.requestFocus();
        }
        @Override
        public void cancelEdit() {
            super.cancelEdit();
            checkBox.setDisable(true);
        }
        public void commitEdit(Boolean value) {
            super.commitEdit(value);
            checkBox.setDisable(true);
        }
        @Override
        public void updateItem(Boolean item, boolean empty) {
            super.updateItem(item, empty);
            if (!isEmpty()) {
                checkBox.setSelected(item);
            }
        }
    }

当然,点击事件的get set方法记得一起改了:

table.setRowFactory(tv -> {
			TableRow<FileSearch> row = new TableRow<>();
			row.setOnMouseClicked(event -> {
				if(!row.isEmpty()) {
					String rowData = row.getItem().lastName.getValue();
					String[] list = rowData.split("\\\\" );
					rowData = '"' + list[list.length-1].split("\\.")[0] + '"';
					if (row.getItem().getBox()== false) {
						data.get(row.getIndex()).setBox(true);
						table.refresh();
						changeList.add(rowData);
					}else {
						row.getItem().setBox(false);
						table.refresh();
						remove(changeList, rowData);
					}
				}
			});
			btSelect.setOnMouseClicked(event -> {
				if(btSelect.getText() == "全選択") {
					btSelect.setText("全選択解除");
				}else {
					btSelect.setText("全選択");
				}
				table.getItems().forEach(e ->{
					if (e.getBox()== false) {
						e.setBox(true);
						table.refresh();
						changeList.add(e.lastName.getValue());
					}else {
						e.setBox(false);
						table.refresh();
						remove(changeList, e.lastName.getValue());
					}
				});
			});
			return row;
		});
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值