如果设置了 HijrahChronology,DatePicker 的 setDayCellFactory 中的 setDisable() 将不起作用
setDisable() inside DatePicker's setDayCellFactory not working if HijrahChronology is set
我正在尝试使用 JavaFX 8 的 DatePicker 禁用不在 [今天,今天 + 1 年] 范围内的日期,类似于 the example in the official tutorial。这是代码:
sample.fxml:
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.DatePicker?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<DatePicker fx:id="dpDate"/>
</GridPane>
Main.java:
package sample;
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.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.util.Callback;
import javafx.util.StringConverter;
import java.net.URL;
import java.time.LocalDate;
import java.time.chrono.HijrahChronology;
import java.time.format.DateTimeFormatter;
import java.util.ResourceBundle;
public class Controller implements Initializable
{
private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
@FXML private DatePicker dpDate;
@Override
public void initialize(URL location, ResourceBundle resources)
{
Callback<DatePicker, DateCell> dayCellFactory = dp -> new DateCell()
{
@Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
if(item.isBefore(LocalDate.now()) || item.isAfter(LocalDate.now().plusYears(1)))
{
setStyle("-fx-background-color: #ffc0cb; -fx-text-fill: darkgray;");
setDisable(true);
}
}
};
StringConverter converter = new StringConverter<LocalDate>()
{
@Override
public String toString(LocalDate date)
{
if(date != null) return dateFormatter.format(date);
else return "";
}
@Override
public LocalDate fromString(String string)
{
if(string != null && !string.isEmpty())
{
LocalDate date = LocalDate.parse(string, dateFormatter);
if(date.isBefore(LocalDate.now()) || date.isAfter(LocalDate.now().plusYears(1)))
{
return dpDate.getValue();
}
else return date;
}
return null;
}
};
dpDate.setDayCellFactory(dayCellFactory);
dpDate.setConverter(converter);
dpDate.setPromptText("dd/MM/yyyy");
dpDate.setValue(LocalDate.now());
dpDate.setChronology(HijrahChronology.INSTANCE);
}
}
仅当我删除最后一行 dpDate.setChronology(HijrahChronology.INSTANCE);
并将其保留为默认值 IsoChronology
.
时,此示例才有效(即用户不能 select 超出范围)
我试过在updateItem()
里面消费click事件:
@Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
if(item.isBefore(LocalDate.now()) || item.isAfter(LocalDate.now().plusYears(1)))
{
setStyle("-fx-background-color: #ffc0cb; -fx-text-fill: darkgray;");
setDisable(true);
addEventFilter(MouseEvent.MOUSE_CLICKED, e -> e.consume());
}
}
它适用于当月(不能 select 编辑今天之前的日子)。但是,如果我转到接下来的几个月,它会阻止用户 select 从允许范围内获取一天。
这绝对是一个错误。有解决方法吗?如何访问日期选择器弹出窗口?也许我可以将一个侦听器附加到更改月份页面的按钮,然后遍历所有 say 单元格并手动禁用超出范围的日期。
我在 JavaFX JIRA 中提交了错误报告,他们将在下一次更新 8u60 时修复它。这是 Leif Samuelsson 建议的解决方法:
This is a bug in com.sun.javafx.scene.control.skin.DatePickerHijrahContent. It overrides updateDayCells() and calls setDisable(false) on all cells after super has called updateItem() on the custom cell factory.
A workaround is to wrap the setDisable() call in a Platform.runLater():
Platform.runLater(() -> {
setDisable(true);
});
我正在尝试使用 JavaFX 8 的 DatePicker 禁用不在 [今天,今天 + 1 年] 范围内的日期,类似于 the example in the official tutorial。这是代码:
sample.fxml:
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.DatePicker?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<DatePicker fx:id="dpDate"/>
</GridPane>
Main.java:
package sample;
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.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.util.Callback;
import javafx.util.StringConverter;
import java.net.URL;
import java.time.LocalDate;
import java.time.chrono.HijrahChronology;
import java.time.format.DateTimeFormatter;
import java.util.ResourceBundle;
public class Controller implements Initializable
{
private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
@FXML private DatePicker dpDate;
@Override
public void initialize(URL location, ResourceBundle resources)
{
Callback<DatePicker, DateCell> dayCellFactory = dp -> new DateCell()
{
@Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
if(item.isBefore(LocalDate.now()) || item.isAfter(LocalDate.now().plusYears(1)))
{
setStyle("-fx-background-color: #ffc0cb; -fx-text-fill: darkgray;");
setDisable(true);
}
}
};
StringConverter converter = new StringConverter<LocalDate>()
{
@Override
public String toString(LocalDate date)
{
if(date != null) return dateFormatter.format(date);
else return "";
}
@Override
public LocalDate fromString(String string)
{
if(string != null && !string.isEmpty())
{
LocalDate date = LocalDate.parse(string, dateFormatter);
if(date.isBefore(LocalDate.now()) || date.isAfter(LocalDate.now().plusYears(1)))
{
return dpDate.getValue();
}
else return date;
}
return null;
}
};
dpDate.setDayCellFactory(dayCellFactory);
dpDate.setConverter(converter);
dpDate.setPromptText("dd/MM/yyyy");
dpDate.setValue(LocalDate.now());
dpDate.setChronology(HijrahChronology.INSTANCE);
}
}
仅当我删除最后一行 dpDate.setChronology(HijrahChronology.INSTANCE);
并将其保留为默认值 IsoChronology
.
我试过在updateItem()
里面消费click事件:
@Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
if(item.isBefore(LocalDate.now()) || item.isAfter(LocalDate.now().plusYears(1)))
{
setStyle("-fx-background-color: #ffc0cb; -fx-text-fill: darkgray;");
setDisable(true);
addEventFilter(MouseEvent.MOUSE_CLICKED, e -> e.consume());
}
}
它适用于当月(不能 select 编辑今天之前的日子)。但是,如果我转到接下来的几个月,它会阻止用户 select 从允许范围内获取一天。
这绝对是一个错误。有解决方法吗?如何访问日期选择器弹出窗口?也许我可以将一个侦听器附加到更改月份页面的按钮,然后遍历所有 say 单元格并手动禁用超出范围的日期。
我在 JavaFX JIRA 中提交了错误报告,他们将在下一次更新 8u60 时修复它。这是 Leif Samuelsson 建议的解决方法:
This is a bug in com.sun.javafx.scene.control.skin.DatePickerHijrahContent. It overrides updateDayCells() and calls setDisable(false) on all cells after super has called updateItem() on the custom cell factory.
A workaround is to wrap the setDisable() call in a Platform.runLater():
Platform.runLater(() -> { setDisable(true); });