使用自定义datepicker tablecell javafx过滤表时问题
我正在尝试使用DatePicker制作自定义的表单元格。并在表中过滤的列表,该列表根据单选按钮选择过滤内容。当我选择一个单元的日期时,一切正常。
ScreenShot 1
但是,当试图过滤和发射谓词时,日期向下看表的底部。重新选择旧的广播按钮时,它会出现在正确的行中。
ScreenShot 2
有什么想法吗?
我的控制器:
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.Callback;
import javafx.util.converter.IntegerStringConverter;
import java.net.URL;
import java.time.LocalDate;
import java.util.ResourceBundle;
public class Controller implements Initializable {
@FXML
private TableColumn<SetterGetter, String> colStatus;
@FXML
private TableColumn<SetterGetter, Integer> colCode;
@FXML
private TableColumn<SetterGetter, LocalDate> colDueDate;
@FXML
private TableColumn<SetterGetter, String> colName;
@FXML
private RadioButton rdAll;
@FXML
private RadioButton rdDelayed;
@FXML
private RadioButton rdDone;
@FXML
private TableView<SetterGetter> tableTasks;
private RadioButton selectedRadioButton;
ObservableList<SetterGetter> mainTaskList = FXCollections.observableArrayList();
FilteredList<SetterGetter> tableTaskList = new FilteredList<>(mainTaskList, p -> true);
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
selectedRadioButton = rdAll;
colCode.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<SetterGetter, Integer>>() {
@Override
public void handle(TableColumn.CellEditEvent<SetterGetter, Integer> event) {
SetterGetter row = event.getRowValue();
row.setId(event.getNewValue());
}
});
colName.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<SetterGetter, String>>() {
@Override
public void handle(TableColumn.CellEditEvent<SetterGetter, String> event) {
SetterGetter row = event.getRowValue();
row.setName(event.getNewValue());
}
});
colStatus.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<SetterGetter, String>>() {
@Override
public void handle(TableColumn.CellEditEvent<SetterGetter, String> event) {
SetterGetter row = event.getRowValue();
row.setStatus(event.getNewValue().equals("منجز") ? 0 : 1);
}
});
colCode.setCellValueFactory(b -> new SimpleIntegerProperty(b.getValue().getId()).asObject());
colDueDate.setCellValueFactory(b -> b.getValue().getDate());
colName.setCellValueFactory(b -> new SimpleStringProperty(b.getValue().getName()));
colStatus.setCellValueFactory(b -> new SimpleStringProperty(
b.getValue().getStatus() == 0 ? "منجز"
: "لم ينجز بعد")
);
colCode.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
colName.setCellFactory(TextFieldTableCell.forTableColumn());
colStatus.setCellFactory(ComboBoxTableCell.forTableColumn(FXCollections.observableArrayList(
"منجز",
"لم ينجز بعد")
)
);
colDueDate.setCellFactory(new Callback<TableColumn<SetterGetter, LocalDate>, TableCell<SetterGetter, LocalDate>>() {
@Override
public TableCell<SetterGetter, LocalDate> call(TableColumn<SetterGetter, LocalDate> setterGetterStringTableColumn) {
return new DatePickerTableCell();
}
});
mainTaskList.addAll(
new SetterGetter(0, null, null, 1),
new SetterGetter(1, null, null, 1)
);
tableTasks.setItems(tableTaskList);
}
@FXML
void addCheck(ActionEvent event) {
mainTaskList.add(new SetterGetter(0,
null,
null,
0)
);
}
@FXML
void selectRadioButton(ActionEvent event) {
if (event.getSource() != selectedRadioButton) {
RadioButton newRadio = (RadioButton) event.getSource();
newRadio.setStyle("-fx-font-family:arial;-fx-font-size:14;-fx-font-weight:bold;-fx-border-color:red;-fx-border-radius:20;");
selectedRadioButton.setStyle("-fx-font-family:arial;-fx-font-size:14;-fx-font-weight:bold;");
selectedRadioButton = newRadio;
}
firePredicate();
}
private void firePredicate() {
tableTaskList.setPredicate(p -> {
if (selectedRadioButton.equals(rdDone) && p.getStatus() != 0)
return false;
else if (selectedRadioButton.equals(rdDelayed) && p.getStatus() != 1)
return false;
else return true;
});
}
}
datePickerTableCell类:
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TableCell;
import java.time.LocalDate;
public class DatePickerTableCell extends TableCell<SetterGetter, LocalDate> {
private final DatePicker datePicker = new DatePicker();
public DatePickerTableCell() {
super();
}
@Override
public void startEdit() {
super.startEdit();
setGraphic(datePicker);
setText(null);
datePicker.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
commitEdit(datePicker.getValue());
}
});
}
@Override
public void commitEdit(LocalDate s) {
super.commitEdit(s);
setText(s.toString());
setGraphic(null);
setItem(s);
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(datePicker.getValue() == null ? null : datePicker.getValue().toString());
setGraphic(null);
}
}
Settergetter类:
import javafx.beans.property.ObjectProperty;
import java.time.LocalDate;
public class SetterGetter {
int id;
String name;
ObjectProperty<LocalDate> date;
int status;
public SetterGetter(int id, String name, ObjectProperty<LocalDate> date, int status) {
this.id = id;
this.name = name;
this.date = date;
this.status = status;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ObjectProperty<LocalDate> getDate() {
return date;
}
public void setDate(ObjectProperty<LocalDate> date) {
this.date = date;
}
}
主类:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setScene(new Scene(root, 565, 551));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML文件:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="551.0" prefWidth="565.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<TableView fx:id="tableTasks" editable="true" layoutX="16.0" layoutY="163.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="400.0" prefWidth="554.0" style="-fx-font-family: arial; -fx-font-size: 15;" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0">
<columns>
<TableColumn fx:id="colDueDate" prefWidth="112" style="-fx-font-family: arial; -fx-font-size: 15;" text="التاريخ" />
<TableColumn fx:id="colStatus" prefWidth="112" style="-fx-font-family: arial; -fx-font-size: 15;" text="الحالة" />
<TableColumn fx:id="colName" prefWidth="112" style="-fx-font-family: arial; -fx-font-size: 15;" text="الأسم" />
<TableColumn fx:id="colCode" prefWidth="112" style="-fx-font-family: arial; -fx-font-size: 15;" text="الكود" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<HBox alignment="CENTER" layoutX="160.0" layoutY="27.0" spacing="15.0">
<children>
<RadioButton fx:id="rdDelayed" mnemonicParsing="false" onAction="#selectRadioButton" style="-fx-font-family: arial; -fx-font-size: 14; -fx-font-weight: bold;" text="لم ينجز بعد">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<toggleGroup>
<ToggleGroup fx:id="radioGroup" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="rdDone" mnemonicParsing="false" onAction="#selectRadioButton" style="-fx-font-family: arial; -fx-font-size: 14; -fx-font-weight: bold;" text="منجز" toggleGroup="$radioGroup">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</RadioButton>
<RadioButton fx:id="rdAll" mnemonicParsing="false" onAction="#selectRadioButton" selected="true" style="-fx-font-family: arial; -fx-font-size: 14; -fx-font-weight: bold; -fx-border-color: red; -fx-border-radius: 20 20 20 20;" text="الكل" toggleGroup="$radioGroup">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</RadioButton>
</children>
</HBox>
<Button layoutX="473.0" layoutY="31.0" mnemonicParsing="false" onAction="#addCheck" prefHeight="34.0" prefWidth="77.0" style="-fx-font-family: arial; -fx-font-size: 18;" text="إضافة">
<font>
<Font name="Arial" size="17.0" />
</font>
</Button>
</children>
</AnchorPane>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的演示中缺少多件事。其中,@Jewelsea在评论中已经提到了一个。
问题1:
我注意到您尚未添加日期列的提交事件。您需要将值(日期)持续到行对象中,以在过滤时获得正确的结果。
初始化方法中的代码将是这样的:
问题2 :
正如@Jewelsea所述,在定义自定义单元时,您需要覆盖TableCell的UpdateItem()方法。 DatePickerTableCell中的代码将为:
UpdateEtem中的丢失IF-ELSE条件是您实际发行单元格值的主要原因。
虚拟流将单元格重新放置,并可以将其放置在任何地方。我们有责任确保在调用更新时正确渲染。如果缺少IF-ELSE条件,则可以看到用错误的值使用的单元格。
问题#3 :不完全是问题;)
在Settergetter类中使用适当的命名惯例/可观察性属性的命名惯例。
There are multiple things missing in your demo. Among that, one is already mentioned by @jewelsea in his comment.
Issue#1:
I noticed that you have not added a commit event for the date column. You need to persist the value(date) into the row object to get correct results when filtering.
Your code in the initialize method will be something like this:
Issue#2:
As mentioned by @jewelsea, you need to override the updateItem() method of the TableCell when defining a custom cell. The code in the DatePickerTableCell will be like:
The missing if-else condition in the updateItem is the main cause for your actual issue of the cell value to be in inappropriate place.
A VirtualFlow reuses the cells and can place it any where. It is our duty to ensure that it renders correctly when the updateItem is called. If the if-else condition is missing, you can see cell being used with wrong value.
Issue#3: Not exactly an issue ;)
Use proper naming conventions for the setter/getter of observable properties in the SetterGetter class.
问题的基本问题是隐藏在日期列中包含值的数据行时的视觉伪像。该人工制品的原因是自定义单元实现中
updateItem(s,boolean)
的缺失替代,这在重复使用该单元时会导致不正确的单元格状态(如注释和 sai's 答案)。解决方案是实现该方法。锤击中:updateItem在单元格中指定, indexedCell的直接后代既不是listcell也不是listcell,tree-/tablecell也不是treecell-覆盖它可以做任何有用的事情。这意味着每个自定义单元的实现都扩展了这些必须自己做到这一点。 API文档可以覆盖更新的方法,以允许单元格的完整自定义不太正确。
问题可能是:如何正确覆盖它?其目的是根据项目更新单元格的视觉状态。有两个基本规则:
:
注意:这与API doc中的示例略有不同在实际设置与项目相关的图形时(无需重置空状态的图形没有意义;)
下一个问题可能是编辑:通常,用于编辑的单元格仅具有输入控件(FI a Textfield)编辑模式。这意味着在切换编辑状态时显示/隐藏这些内容。这样做的责任在于编辑lifecylce方法(start-/cancel-/consitedIt)。
所有应用于下面的自定义datepickertablecell:
:这种严格的关注点(依赖性视觉效果与依赖视觉效果)是可能的,因为FX17可以修复了一堆具有单元格后单元格式状态的错误使用(请参阅发行说明,fi jdk-8264127 对于ListCell, jdk-8265206 for tree-/tablecell, jdk-8265210 对于treecell及相关))
一种替代性自定义datepickertablecell :(
主要是无关的)围绕属性的API设计的注释:
通常,属性价值不应为无效,并且
在此中 无关紧要,并且不可能无效。位置,TableColumn的默认提交处理程序将按预期工作,并且无需安装自定义提交处理程序。
The base problem in the question is the visual artefact when hiding a data row that contains a value in the date column. The reason for that artefact is the missing override of
updateItem(S, boolean)
in the custom cell implementation which leads to incorrect cell state when that cell is re-used (as already noted in comments and Sai's answer). The solution is to implement the method.Hammering in: updateItem is specified in Cell and none of the direct descendants of IndexedCell - that is neither ListCell nor Tree-/TableCell nor TreeCell - override it to do anything useful. Which implies that each and every custom cell implementation extending those has to do it itself. The api doc the updateItem method can be overridden to allow for complete customisation of the cell is not quite correct.
Problem might be: how to override it correctly? Its purpose is to update the visual state of the cell based on the item. There are two basic rules:
Example:
Note: this is slightly different from the example in the api doc in actually setting an item-related graphic (without, resetting the graphic for the empty state doesn't make sense ;)
Next problem might be editing: typically, a cell meant for editing has an input control (f.i. a TextField) only while in editing mode. This implies showing/hiding those when toggling editing state. The responsibility for doing so resides in the edit lifecylce methods (start-/cancel-/commitEdit).
All applied to a custom DatePickerTableCell below:
Caveat: this strict separation of concerns (editing dependent visuals vs item dependent visuals) is possible since fx17 which fixes a bunch of bugs with cell editing state after cell re-use (see the release notes, f.i. JDK-8264127 for ListCell, JDK-8265206 for Tree-/TableCell, JDK-8265210 for TreeCell and related)
An alternative custom DatePickerTableCell:
(Mostly unrelated) note on api design around Properties:
Typically, property valued fields should be not null and immutable
With that in place, TableColumn's default commit handler will work as expected and there's no need to install a custom commit handler.