Java Custom SpinnerDateModel只能编辑小时和分钟

时间:2018-02-16 20:26:49

标签: java jspinner

我正在尝试创建一个小时和分钟的JSpinner编辑器。 JSpinner很容易

JSpinner startSpinner = new JSpinner();
SpinnerWindowModel spinnerModel = new SpinnerWindowModel();
startSpinner.setModel(spinnerModel);
JSpinner.DateEditor editor = new JSpinner.DateEditor(startSpinner, "HH:mm");
startSpinner.setEditor(editor);

Spinner WindowModel是:

public SpinnerWindowModel() {
    super();
    Calendar vCal = Calendar.getInstance();
    vCal.set(Calendar.HOUR_OF_DAY, 8);
    vCal.set(Calendar.MINUTE, 0);
    vCal.set(Calendar.SECOND, 0);
    setValue(vCal.getTime());

    setCalendarField(Calendar.MINUTE);

    vCal.set(Calendar.HOUR_OF_DAY, 6);
    vCal.set(Calendar.MINUTE, 0);
    vCal.set(Calendar.SECOND, 0);
    setStart(vCal.getTime());

    vCal.set(Calendar.HOUR_OF_DAY, 18);
    vCal.set(Calendar.MINUTE, 45);
    vCal.set(Calendar.SECOND, 0);
    setEnd(vCal.getTime());
}

@Override
public Object getPreviousValue() {
    Object obj = super.getPreviousValue();
    int fld = getCalendarField();
    System.out.println("GPV: " + fld);

    return obj; 
}

@Override
public Object getNextValue() {
    Object obj = super.getNextValue();
    int fld = getCalendarField();
    System.out.println("GNV: " + fld);
    return obj;
}

getNext / PreviousValue这两个方法目前只监视调用方法以及调用它们的字段。使用受限制的编辑器,这些方法不会被称为

如果我将编辑器更改为更完整的字段集,它就像我期望的那样工作。小时和分钟字段可编辑且正确。编辑简化编辑器需要做些什么吗?

editor = new JSpinner.DateEditor(startSpinner, "dd/MM/yyyy HH:mm:ss.SS");

1 个答案:

答案 0 :(得分:1)

所以,当我使用你的模型时,它不起作用,但是当我使用像...这样的东西时

    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);

    Date startTime = cal.getTime();
    cal.set(Calendar.HOUR, 23);
    cal.set(Calendar.MINUTE, 59);
    Date endTime = cal.getTime();

    System.out.println(startTime);
    System.out.println(endTime);

    // The Calendar field seems to get ignored and overriden 
    // by the UI delegate based on what part of the field
    // the cursor is current on (hour or minute)
    SpinnerDateModel model = new SpinnerDateModel(startTime, null, endTime, Calendar.MINUTE);
    JSpinner spinner = new JSpinner(model);
    spinner.setEditor(new JSpinner.DateEditor(spinner, "HH:mm"));

    spinner.setValue(startTime);

工作正常

Spinner

此时我的“建议”不是使用自定义模型,而是通过所需的工厂方法手动构建模型

更新...

由于围绕JSpinnerJForamttedTextField的复杂性,我放弃了试图让JSpinner来处理时间。相反,我通常会回到使用单独的字段来管理状态的复杂性

我开始修改你的模型......

public class SpinnerWindowModel extends SpinnerNumberModel {

    private Calendar calendar;
    private int calendarField;

    public SpinnerWindowModel(int calendarField, Calendar calendar, int value, int min, int max, int step) {
        super(value, min, max, step);
        this.calendar = calendar;
    }

    @Override
    public void setValue(Object value) {
        super.setValue(value);
        System.out.println(value);
    }

    public int getCalendarField() {
        return calendarField;
    }

    @Override
    public Object getPreviousValue() {
        Object obj = super.getPreviousValue();
        if (obj instanceof Integer)  {
            int fld = getCalendarField();
            calendar.set(fld, (int)obj);

            return obj;
        }

        return getValue();
    }

    @Override
    public Object getNextValue() {
        Object obj = super.getNextValue();
        if (obj instanceof Integer)  {
            int fld = getCalendarField();
            calendar.set(fld, (int)obj);

            return obj;
        }

        return getValue();
    }
}

然后将其应用于字段......

Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);

Date startTime = cal.getTime();
cal.set(Calendar.HOUR, 23);
cal.set(Calendar.MINUTE, 59);
Date endTime = cal.getTime();

System.out.println(startTime);
System.out.println(endTime);

SpinnerWindowModel hourModel = new SpinnerWindowModel(Calendar.HOUR, cal, 0, 0, 23, 1);
SpinnerWindowModel minuteModel = new SpinnerWindowModel(Calendar.HOUR, cal, 0, 0, 59, 15);

JSpinner hour = new JSpinner(hourModel);
JSpinner minute = new JSpinner(minuteModel);

add(hour);
add(new JLabel(":"));
add(minute);

现在,回到这一点是,分钟字段不会滚动小时字段。我确实考虑过在分钟模型上使用更改监听器,但问题是,你真的不知道该字段是上升还是下降,所以没有简单的方法来确定你应该按小时滚动的方式。

我会花费这个概念,使用两个单独的JTextField s(应用了适当的DocumentFilter)和一个“roll”控件。这个想法是,滚动控制(即向上和向下按钮)会影响聚焦场。然后,您可以在触发滚动控件时提供适当的状态信息,以允许字段确定它们应该执行的操作以及它们应如何相互影响。

其中很多内容可以汇总到一个模型中,该模型控制Calendar(或最好是LocalTime)对象,这将更改基础日期值并通知他们需要的字段变化

我相信这种方法可以为您提供为小时和分钟提供不同步进率所需的控制水平,同时为用户交互提供灵活性(如果我需要,我可以手动输入数字或通过滚动控制输入数字到)

更新......最后......

因此,基于this answer,基础JFormattedTextField无法验证该值,因为时间格式丢弃值的“日期”部分只保留此时间,这就是最小/最大值检查失败。

相反,我们需要将min / max值的“date”部分定义为我们可以控制(并更容易定义)的东西。这也意味着任何输入都必须限制在这个特定的时间点

Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(1970, Calendar.JANUARY, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);

Date startTime = cal.getTime();

cal.set(1970, Calendar.JANUARY, 23, 59, 0);
cal.set(Calendar.MILLISECOND, 0);
Date endTime = cal.getTime();

System.out.println(startTime);
System.out.println(endTime);

Calendar value = Calendar.getInstance();
value.set(1970, Calendar.JANUARY, 0, 0, 0);
value.set(Calendar.MILLISECOND, 0);

System.out.println(value.getTime());

// The Calendar field seems to get ignored and overriden 
// by the UI delegate based on what part of the field
// the cursor is current on (hour or minute)
SpinnerDateModel model = new SpinnerDateModel(value.getTime(), startTime, endTime, Calendar.MINUTE);
JSpinner spinner = new JSpinner(model);
spinner.setEditor(new JSpinner.DateEditor(spinner, "HH:mm"));
spinner.setValue(value.getTime());

add(spinner);

然后让我更新你的模型以支持多步状态......

public class SpinnerWindowModel extends SpinnerDateModel {

    public SpinnerWindowModel() {
        super();
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set(1970, Calendar.JANUARY, 0, 0, 0);
        cal.set(Calendar.MILLISECOND, 0);

        Date startTime = cal.getTime();

        cal.set(1970, Calendar.JANUARY, 23, 59, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date endTime = cal.getTime();

        System.out.println(startTime);
        System.out.println(endTime);

        Calendar value = Calendar.getInstance();
        value.set(1970, Calendar.JANUARY, 0, 0, 0);
        value.set(Calendar.MILLISECOND, 0);

        setStart(startTime);
        setEnd(endTime);
        setValue(value.getTime());
        setCalendarField(Calendar.MINUTE);
    }

    @Override
    public Object getPreviousValue() {
        int fld = getCalendarField();

        Object value = super.getPreviousValue();

        if (fld == Calendar.MINUTE) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(getDate());
            cal.add(Calendar.MINUTE, -15);
            value = cal.getTime();
        }

        return value;
    }

    @Override
    public Object getNextValue() {
        int fld = getCalendarField();
        Object value = super.getNextValue();

        if (fld == Calendar.MINUTE) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(getDate());
            cal.add(Calendar.MINUTE, 15);
            value = cal.getTime();
        }

        return value;
    }
}