JDK1.7版本下JavaFx自定义日期选择器
jdk1.7版本下的javafx是不支持日期选择器的,而可用的日期选择器DatePicker是从jdk1.8才开始引入的,并且只有jdk1.8才有新的时间类型。
所以自定义的日期选择器是jdk1.7版本下javafx的唯一出路。
下面是自定义javaFx日期选择器的代码:
日期选择器基础
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* <p>
* 日期选择器基础
* </p>
*
* @author xj
* @since 2023/2/28 19:38
*/
public class BaseDatePicker {
/** 初始化日历 */
protected Calendar c = Calendar.getInstance();
/** 年 */
protected int year = c.get(Calendar.YEAR);
/** 月 */
protected int month = c.get(Calendar.MONTH) + 1;
/** 日 */
protected int date = c.get(Calendar.DATE);
/** 小时 */
protected int hour = c.get(Calendar.HOUR_OF_DAY);
/** 分钟 */
protected int minute = c.get(Calendar.MINUTE);
/** 秒钟 */
protected int second = c.get(Calendar.SECOND);
/** x,y */
protected double x,y;
/** 时间选择框容器 */
protected HBox timeCombobox;
/** 小时选择框 */
protected ComboBox<String> hourCombobox;
/** 分钟选择框 */
protected ComboBox<String> minuteCombobox;
/** 秒钟选择框 */
protected ComboBox<String> secondCombobox;
/** 是否带有分秒 */
protected Boolean withSecond;
/** 是否是第一次进入 */
protected Boolean isFirstComing;
/** 日期选择器框 */
protected FlowPane datePick;
/** 显示时间文本框 */
public TextField timeField;
/** 年标签 */
protected Label yearLabel;
/** 月标签 */
protected Label monthLabel;
/** 当前选择的日期时间 */
protected String currentDateTime;
/** 方便外部获取文本输入框 */
public TextField getTimeField() {
return timeField;
}
/** 悬浮按钮样式 */
protected static final String HOVERED_BUTTON_STYLE = "-fx-text-fill: white;-fx-background-color: #5b8cff;";
/** 普通按钮样式 */
protected static final String NORMAL_BUTTON_STYLE = "-fx-text-fill: black;-fx-background-color: transparent;";
/**
* 时间月份过滤
* @param val 数字
* @return 字符串
*/
protected String timeFilter(int val){
return val < 10 ? "0" + val : String.valueOf(val);
}
/**
* 获取月份
* @param val 月份数字
* @return 月份
*/
protected static int getMonth(int val){
if(val > 12) {
return 1;
} else if(val < 1) {
return 12;
}else {
return val;
}
}
/**
* 获取某月中天数
* @param curMonth 月份
* @return 某月中天数
*/
protected int getDaysOfMonth(Integer curMonth) {
Date dateTime = new Date(curMonth == 0 ? (year - 1) : year, curMonth==0 ? (12) : curMonth,0);
return dateTime.getDate();
}
/**
* 获取某一天是星期几
* @param day 天数
* @return 某天是星期几
*/
protected int getWeekNumber(int day){
Date dateTime = new Date(year, month - 1, day);
c.setTime(dateTime);
int dayOfWeek = c.get(Calendar.DAY_OF_WEEK)-2;
return dayOfWeek < 0 ? 6 : dayOfWeek;
}
/**
* 字符串通过格式转换日期
* @param format 格式
* @param timeValStr 字符串
* @return 转换日期
* @throws ParseException 转换异常
*/
protected Date parseDate(String format, String timeValStr) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
return simpleDateFormat.parse(timeValStr);
}
/**
* 设置下拉框参数
* @param range 总计数
* @param items 队列
*/
protected void setRange(int range, ObservableList<String> items){
for (int i = 0; i < range; i++) {
if(i < 10){
items.add("0" + i);
}else{
items.add(String.valueOf(i));
}
}
}
}
常量
/**
* <p>
* 常量
* <p>
*
* @author xj
* @since 2023/2/18 19:11
*/
public interface Constant {
/** 星期栏 */
String[] WEEK_ITEMS = new String[]{"日", "一", "二", "三", "四", "五", "六"};
}
移动工具类
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import java.util.List;
/**
* <p>
* 移动工具类
* <p>
*
* @author xj
* @since 2023/2/8 19:59
*/
public class DragUtil {
public static void addDragListener(Stage stage, Node root) {
new DragListener(stage).enableDrag(root);
}
public static void addDragListener(Stage stage, List<Node> nodeList){
for (Node node : nodeList) {
new DragListener(stage).enableDrag(node);
}
}
static class DragListener implements EventHandler<MouseEvent> {
private double xOffset = 0;
private double yOffset = 0;
private final Stage stage;
public DragListener(Stage stage) {
this.stage = stage;
}
@Override
public void handle(MouseEvent event) {
event.consume();
if (event.getEventType() == MouseEvent.MOUSE_PRESSED) {
xOffset = event.getSceneX();
yOffset = event.getSceneY();
} else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
stage.setX(event.getScreenX() - xOffset);
if(event.getScreenY() - yOffset < 0) {
stage.setY(0);
}else {
stage.setY(event.getScreenY() - yOffset);
}
}
}
public void enableDrag(Node node) {
node.setOnMousePressed(this);
node.setOnMouseDragged(this);
}
}
}
自定义的时间控件选择器
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import yu.lian.common.utils.StringUtils;
import yu.lian.fx.FxApplication;
import yu.lian.fx.common.xfx.DragUtil;
import yu.lian.fx.common.xfx.base.BaseDatePicker;
import yu.lian.fx.common.xfx.util.XjAlertUtil;
import yu.lian.fx.common.xfx.util.XjImageUtil;
import java.text.ParseException;
import java.util.*;
/**
* <p>
* 自定义的时间控件选择器
* <p>
*
* @author xj
* @since 2023/2/27 19:12
*/
public class MyDatePicker extends BaseDatePicker {
/**
* 初始化
* @param withSecond 是否带着时分秒
*/
public MyDatePicker(Boolean withSecond) {
this.withSecond = withSecond;
// 设置第一次进入
this.isFirstComing = true;
// 创建输入框
timeField = new TextField();
// 创建日期选择
datePick = new FlowPane();
// 年
yearLabel = new Label(String.valueOf(year));
// 月
monthLabel = new Label(timeFilter(month));
}
/**
* 获取日期控件
* @return 节点
*/
public HBox getDateTimeTool(){
HBox hBox = new HBox();
timeField.setEditable(false);
timeField.setPrefHeight(30);
timeField.setPrefWidth(250);
timeField.setStyle("-fx-border-radius: 20;-fx-background-radius: 20;");
// 选择日期按钮
Button btn = new Button("", XjImageUtil.createImage(25, "/static/image/date-bg.png"));
btn.setStyle("-fx-background-color:transparent;-fx-cursor:hand;-fx-background-position:center;");
btn.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent oa) {
x = oa.getScreenX() - oa.getX();
y = oa.getScreenY() - oa.getY();
showDatePicker();
}
});
Button btnCancel = new Button("", XjImageUtil.createImage(20, "/static/image/forbidden.png"));
String cancelStyle = ("-fx-translate-x:-30;-fx-translate-y:1;-fx-opacity:1;")+
"-fx-background-color:transparent;-fx-pref-width:22;-fx-cursor:hand;" +
"-fx-background-repeat:no-repeat;-fx-background-position:center;";
btnCancel.setStyle(cancelStyle);
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent oa) {
setCalendarTime();
timeField.clear();
}
});
StackPane stackPane = new StackPane();
stackPane.setAlignment(Pos.CENTER_RIGHT);
// 第一层为:textField
stackPane.getChildren().add(timeField);
// 第二层为:清除按钮
stackPane.getChildren().add(btnCancel);
// 第三层为:日期弹框按钮
stackPane.getChildren().add(btn);
hBox.getChildren().addAll(stackPane);
return hBox;
}
/**
* 初始化当前日期时间
*/
public void setCalendarTime(){
//可以对每个时间域单独修改
Calendar calendar = Calendar.getInstance();
year = calendar.get(Calendar.YEAR);
month = calendar.get(Calendar.MONTH) + 1;
date = calendar.get(Calendar.DATE);
hour = calendar.get(Calendar.HOUR_OF_DAY);
minute = calendar.get(Calendar.MINUTE);
second = calendar.get(Calendar.SECOND);
}
/**
* 显示日期选择框
*/
private void showDatePicker() {
// 初始化日期
initializationTime();
final Stage stage = new Stage();
// 设置弹框为APPLICATION_MODAL模式
stage.initModality(Modality.APPLICATION_MODAL);
//隐藏默认标题栏
stage.initStyle(StageStyle.TRANSPARENT);
VBox vBox = new VBox();
vBox.setId("layout");
vBox.setStyle("-fx-background-color:transparent;");
//日期(年月日)主体
VBox main = new VBox();
createMain(stage, main);
vBox.getChildren().add(main);
Scene scene = new Scene(vBox, 365, 600);
scene.getStylesheets().add(Objects.requireNonNull(
FxApplication.class.getResource("/static/css/datePicker.css")).toExternalForm());
stage.setScene(scene);
stage.setX(x+(withSecond?15:25));
stage.setY(y-(withSecond?10:15));
stage.showAndWait();
}
/**
* 创建主要窗体
* @param stage 窗体
* @param main 主控件
*/
private void createMain(final Stage stage, VBox main) {
//时间box
HBox timeLabelBox = new HBox();
timeLabelBox.setStyle("-fx-border-width: 0 0 1 0;-fx-border-color: rgb(180, 180, 180);");
Label label = new Label("日期选择");
HBox.setMargin(label, new Insets(5, 0, 0, 5));
timeLabelBox.getChildren().add(label);
//日期头部拖动
DragUtil.addDragListener(stage, timeLabelBox);
//年月选择
HBox yearMonthBox = new HBox();
yearMonthBox.setId("yearMonthBox");
VBox.setMargin(yearMonthBox, new Insets(20, 0, 0, 0));
yearMonthBox.setAlignment(Pos.CENTER);
setYearMonthContent(yearMonthBox);
//星期
FlowPane flowPane = new FlowPane();
flowPane.setId("weekBox");
VBox.setMargin(flowPane, new Insets(20, 0, 0, 0));
for (String weekItem : MenuConstant.WEEK_ITEMS) {
Label weekLabel = new Label(weekItem);
weekLabel.setPrefWidth(50);
weekLabel.setPrefHeight(50);
weekLabel.setAlignment(Pos.CENTER);
flowPane.getChildren().add(weekLabel);
}
//日期选择
datePick.setId("datePick");
VBox.setMargin(datePick, new Insets(20, 0, 0, 0));
setDatePickContent();
//时间(时分秒)主体
VBox downMain = new VBox();
if(withSecond) {
setDownMain(downMain);
}
VBox.setMargin(downMain, new Insets(20, 0, 0, 0));
HBox hBox = setBtn(stage);
VBox.setMargin(hBox, new Insets(20, 0, 0, 0));
main.getChildren().addAll(timeLabelBox, yearMonthBox, flowPane, datePick, downMain, hBox);
}
/**
* 设置年月调整按钮框
* @param yearMonthBox 年月调整按钮框
*/
private void setYearMonthContent(HBox yearMonthBox){
Button yearLeftArrow = new Button("", XjImageUtil.createImage(20, "/static/image/yearLeftArrow.png"));
yearLeftArrow.setStyle("-fx-background-color: transparent;-fx-background-position:center;-fx-background-repeat:no-repeat;-fx-background-size:50%;");
yearLeftArrow.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
//年减一
year = Integer.parseInt(yearLabel.getText()) - 1;
yearLabel.setText(String.valueOf(year));
setDatePickContent();
}
});
Button yearRightArrow = new Button("", XjImageUtil.createImage(20, "/static/image/yearRightArrow.png"));
yearRightArrow.setStyle("-fx-background-size:50%;-fx-background-position:center;-fx-background-repeat:no-repeat;-fx-background-color: transparent;");
yearRightArrow.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
//年加一
year = Integer.parseInt(yearLabel.getText()) + 1;
yearLabel.setText(String.valueOf(year));
setDatePickContent();
}
});
Button monthLeftArrow = new Button("", XjImageUtil.createImage(20, "/static/image/monthLeftArrow.png"));
monthLeftArrow.setStyle("-fx-background-size:80%;-fx-background-position:center;-fx-background-repeat:no-repeat;-fx-background-color: transparent;");
monthLeftArrow.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
month = getMonth(Integer.parseInt(monthLabel.getText()) - 1);
//月减一
monthLabel.setText(timeFilter(month));
setDatePickContent();
}
});
Button monthRightArrow = new Button("", XjImageUtil.createImage(20, "/static/image/monthRightArrow.png"));
monthRightArrow.setStyle("-fx-background-size:80%;-fx-background-position:center;-fx-background-repeat:no-repeat;-fx-background-color: transparent;");
monthRightArrow.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
//月加一
month = getMonth(Integer.parseInt(monthLabel.getText()) + 1);
monthLabel.setText(timeFilter(month));
setDatePickContent();
}
});
HBox yearAndMonth = new HBox();
yearAndMonth.getChildren().addAll(yearLabel, new Label("年"), monthLabel, new Label("月"));
yearMonthBox.getChildren().addAll(yearLeftArrow, monthLeftArrow, yearAndMonth, monthRightArrow, yearRightArrow);
}
/**
* 填充日期时间
*/
private void setDatePickContent(){
datePick.getChildren().clear();
datePick.setPrefWrapLength(350);
final List<Button> btnList = new ArrayList<>();
//当月总天数
int monthDays = getDaysOfMonth(month);
//前一个月总天数
int lastMonthDays = getDaysOfMonth(month - 1);
//判断当月第一天是星期几, curDay为多少则前一个月所在当前的天数就为多少 getWeekNumber(monthDays)最后一天是星期几
int curDay = getWeekNumber(1);
// 6-getWeekNumber(monthDays) 就为下个月有几天在当前日历
int lastDay = 6 - getWeekNumber(monthDays);
List<Integer> allDayList = new ArrayList<>();
for(int i = (curDay-1); i>-1; i--){
//加入上个月在本日历的几天
allDayList.add(lastMonthDays - i);
}
for(int i=1; i<=monthDays; i++){
//加入本月的日历
allDayList.add(i);
}
for(int i=1;i<=lastDay;i++){
//加入下个月的几天
allDayList.add(i);
}
int size = allDayList.size();
int subDate = (size-lastDay-1);
c.setTime(new Date());
int realYear = c.get(Calendar.YEAR);
int realMonth = c.get(Calendar.MONTH)+1;
for (int i = 0; i < size; i++) {
final int k = allDayList.get(i);
final Button btn = new Button(String.valueOf(k));
btn.setPrefWidth(50);
btn.setPrefHeight(50);
if(year==realYear && month==realMonth && k==date) {
btn.setStyle(HOVERED_BUTTON_STYLE);
}
if(i>=curDay && i<= subDate){
btn.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
btn.setStyle(HOVERED_BUTTON_STYLE);
}
});
btn.setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
btn.setStyle(NORMAL_BUTTON_STYLE);
}
});
btnList.add(btn);
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
for (Button b : btnList) {
b.setStyle(NORMAL_BUTTON_STYLE);
}
btn.setOnMouseEntered(null);
btn.setOnMouseExited(null);
btn.setStyle(HOVERED_BUTTON_STYLE);
date = k;
//设置当前选择日期的时间
setCurrentDateTime();
System.out.println("点击了日期:" + date);
}
});
}else{
btn.setDisable(true);
btn.setStyle("-fx-background-color: #F4F4F4;");
}
datePick.getChildren().add(btn);
}
}
/**
* 设置时间日期
*/
private void setCurrentDateTime(){
currentDateTime = year +"-"+ timeFilter(month)+"-"+timeFilter(date);
if(isFirstComing){
isFirstComing = false;
if(withSecond){
currentDateTime = currentDateTime+" "+timeFilter(hour)+":"+timeFilter(minute)+":"+timeFilter(second);
}
return;
}
if(withSecond && hourCombobox!=null && hourCombobox.getValue()!=null){
currentDateTime = currentDateTime+" "+ hourCombobox.getValue() +":"+ minuteCombobox.getValue()
+":"+ secondCombobox.getValue();
}else{
System.out.println("你选择的日期是:"+currentDateTime);
timeField.setText(currentDateTime);
}
}
/**
* 初始化日期
*/
private void initializationTime() {
try {
//初始化当前日期时间
String timeValStr = timeField.getText();
if (StringUtils.isNotEmpty(timeValStr) && timeValStr.trim().length() > 0) {
Date dateTime;
if(withSecond){
dateTime = parseDate("yyyy-MM-dd HH:mm:ss", timeValStr);
}else {
dateTime = parseDate("yyyy-MM-dd", timeValStr);
}
c.setTime(dateTime);
} else {
setCalendarTime();
}
}catch (ParseException e) {
XjAlertUtil.alertTime("警告", "初始化日期错误!");
}
}
/**
* 设置底部时分秒
* @param downMain 主体节点
*/
public void setDownMain(VBox downMain){
downMain.setStyle("-fx-min-height: 150;-fx-max-height: 150;-fx-min-width:350;-fx-max-width:350;-fx-alignment: center;");
HBox emptyBox = new HBox();
emptyBox.setStyle("-fx-min-height: 5;-fx-max-height: 5;-fx-min-width:330;-fx-max-width:330;-fx-border-style: hidden hidden solid hidden;-fx-border-color:#EBEBEB; ");
//时间box
HBox timeLabelBox = new HBox();
timeLabelBox.setStyle("-fx-min-height: 40;-fx-max-height: 40;-fx-min-width:350;-fx-alignment: CENTER_LEFT;-fx-padding: 10; ");
timeLabelBox.getChildren().add(new Label("时间"));
//时间选择combobox
timeCombobox = new HBox();
timeCombobox.setStyle("-fx-min-height: 30;-fx-max-height: 30;-fx-min-width:350;-fx-alignment: center;");
timeCombobox.getChildren().addAll(getCombo("时"), getCombo("分"), getCombo("秒"));
HBox emptyBox2 = new HBox();
emptyBox2.setStyle("-fx-min-height: 35;-fx-max-height: 35;-fx-min-width:350;");
downMain.getChildren().addAll(emptyBox, timeLabelBox, timeCombobox, emptyBox2);
}
/**
* 获得下拉框
* @param text 文本判断
* @return 下拉框
*/
private HBox getCombo(final String text){
HBox main = new HBox();
main.setStyle("-fx-alignment: center;");
main.prefWidthProperty().bind(timeCombobox.widthProperty().subtract(20).divide(3));
main.prefHeightProperty().bind(timeCombobox.heightProperty());
ComboBox<String> comboBox = new ComboBox<>();
comboBox.prefWidthProperty().bind(main.widthProperty().multiply(2).divide(3));
comboBox.prefHeightProperty().bind(main.heightProperty());
Label label = new Label(" "+text);
label.prefWidthProperty().bind(main.widthProperty().multiply(1).divide(3));
label.prefHeightProperty().bind(main.heightProperty());
comboBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> ov, Number oldv, Number newv) {
if ("时".equals(text) && newv.intValue() != hour) {
setCurrentDateTime();
} else if ("分".equals(text) && newv.intValue() != minute) {
setCurrentDateTime();
} else if ("秒".equals(text) && newv.intValue() != second) {
setCurrentDateTime();
}
}
});
main.getChildren().addAll(comboBox,label);
ObservableList<String> items = FXCollections.observableArrayList();
if("时".equals(text)){
setRange(24,items);
comboBox.setValue(timeFilter(hour));
hourCombobox = comboBox;
}else if("分".equals(text)){
setRange(60,items);
comboBox.setValue(timeFilter(minute));
minuteCombobox = comboBox;
}else if("秒".equals(text)){
setRange(60,items);
comboBox.setValue(timeFilter(second));
secondCombobox = comboBox;
}
comboBox.setItems(items);
return main;
}
/**
* 设置按钮
* @param stage 窗体
*/
private HBox setBtn(final Stage stage) {
//取消和确认按钮box
HBox btnBox = new HBox(20);
btnBox.setStyle("-fx-min-height: 40;-fx-max-height: 40;-fx-min-width:350;" +
"-fx-border-style: solid hidden hidden hidden;-fx-border-color:#EBEBEB;-fx-alignment: center;");
Button confirmBtn = new Button("确认");
Button cancelBtn = new Button("取消");
HBox.setMargin(confirmBtn, new Insets(20, 0, 0, 0));
HBox.setMargin(cancelBtn, new Insets(20, 0, 0, 0));
confirmBtn.setId("confirmBtn");
cancelBtn.setId("cancelBtn");
confirmBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
timeField.setText(currentDateTime);
stage.close();
}
});
cancelBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent oa) {
timeField.clear();
stage.close();
}
});
btnBox.getChildren().addAll(cancelBtn, confirmBtn);
return btnBox;
}
}
用法:
MyDatePicker myDatePicker = new MyDatePicker(true);
myDatePicker.getDateTimeTool();
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。