如何从支持常规文本的JFXtras中对LocalDateTextField进行模拟?

时间:2018-02-06 09:15:04

标签: java jfxtras

我想为用户提供在数据库中搜索的功能。他们应该能够在一列上按文本搜索,在另一列上按日期搜索。但我不想在UI中创建两个单独的字段,我想将它们组合在一个TextField中。 JFXtras中的LocalDateTextField对此非常有用,因为它允许使用方便的选择器选择日期,但也允许输入文本。但是,它会自动解析输入,如果无法将其解析为LocalDate,则该字段将清除(按照定义)。

我的问题是:我可以保留文本,如果有的话我得到LocalDate,或者如果LocalDate字段为null,那么我只得到文本?我试过尝试使用setParseErrorCallback(试图在那里设置文本属性),但似乎删除发生在某个地方。我可以在常规TextField旁边放一个按钮,用LocalDatePicker调用PopOver,但我不确定如何复制它的外观。我如何设计它以使popover像Button一样用渐变着色?我已经尝试过picker.getStyleClass().add("button"),但这会继续悬停发光和填充。

以下是LocalDateTextField选择器的外观:

LocalDateTextField

请注意填充,渐变以及它如何直接位于文本字段下方。这是按下Button时调用的PopOver中的LocalDatePicker:

LocalDatePicker in PopOver

总结:我可以更改LocalDateTextField的行为,如果是,那么如何,如果没有那么我如何设置我自己的实现看起来相同?我已经尝试过查看源文件了,但我无法理解那里的魔法发生在哪里。

1 个答案:

答案 0 :(得分:0)

结束制作我自己的SearchTextField。有一个HBox,把TextField和Button放在那里,Button用LocalDatePicker调用PopOver,选择器用来自JFXtras的以下css设置样式:

.LocalDatePicker {
    -fx-background-color: -fx-body-color;
    -fx-background-insets: 0 0 -1 0,0,1,2;
    -fx-background-radius: 5,5,4,3;
    -fx-padding: 0.466667em 0.333333em 0.35em 0.333333em;
    -fx-text-fill: -fx-text-base-color;
}

然后添加了一些监听器以提供所需的逻辑并完成所有操作。

这里是代码(抱歉)

package view.elements;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.util.Duration;
import jfxtras.scene.control.LocalDatePicker;
import org.controlsfx.control.PopOver;
import org.controlsfx.glyphfont.FontAwesome;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class SearchTextField extends HBox {
    private final TextField field = new TextField();
    private final LocalDatePicker picker = new LocalDatePicker();
    private final PopOver over = new PopOver(picker);
    private final Button searchButton = new Button("Искать");
    private final StringProperty promptTextProperty = new SimpleStringProperty();
    private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");

    public SearchTextField() {
        super();
        field.promptTextProperty().bind(promptTextProperty);
        field.setPrefColumnCount(20);
        over.setArrowSize(0);
        over.setArrowLocation(PopOver.ArrowLocation.TOP_CENTER);
        picker.getStylesheets().add(SearchTextField.class.getResource("datefield.css").toExternalForm());
        picker.getStyleClass().add("LocalDatePicker");
        picker.prefWidthProperty().bind(this.widthProperty());
        picker.setMode(LocalDatePicker.Mode.SINGLE);
        picker.setAllowNull(true);
        final Button showPicker = new Button();
        showPicker.setGraphic(MethodFX.getFontAwesome().create(FontAwesome.Glyph.CALENDAR_ALT));

        showPicker.setOnAction(event -> {
            if (over.isShowing())
                over.hide();
            else
                over.show(field, -2);
        });
        field.textProperty().addListener((obs, oldText, newText) -> {
            if(newText.matches("(^(((0[1-9]|1[0-9]|2[0-8])[.](0[1-9]|1[012]))|((29|30|31)[.](0[13578]|1[02]))|((29|30)[.](0[4,6,9]|11)))[.](19|[2-9][0-9])\\d\\d$)|(^29[.]02[.](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)"))
                picker.localDateProperty().setValue(LocalDate.parse(newText, dateFormatter));
            else
                picker.localDateProperty().setValue(null);
        });
        picker.localDates().addListener((ListChangeListener<LocalDate>) c -> {
            while(c.next() && c.wasAdded()) {
                field.setText(dateFormatter.format(c.getAddedSubList().get(0)));
            }
            over.hide();
        });
        field.focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue && over.isShowing())
                over.hide();
        });

        this.setSpacing(4);
        this.getChildren().addAll(field, showPicker, searchButton);
    }

    public String getText() { return field.getText(); }

    public LocalDate getLocalDate() { return picker.getLocalDate(); }

    public void hidePicker(Duration duration) { if (over.isShowing()) over.hide(duration); }

    public void setOnSearch(EventHandler<ActionEvent> eventHandler) { searchButton.setOnAction(eventHandler); }

    public StringProperty promptTextProperty() {
        return promptTextProperty;
    }

    public void setPromptText(String value) { promptTextProperty.setValue(value); }

    public String getPromptText() { return promptTextProperty.getValue(); }
}