2010-10-06 34 views
6

我有一個使用SpinnerDateModel的JSpinner,該SpinnerDateModel開始於2010年1月1日00:00:00.000結束日期爲2010年1月1日00:12 :34.217。我希望我的JSpinner.DateEditor使用格式HH:mm:ss.SSS,但是微調不會以此格式旋轉。只有當「yyyy」添加到格式時它纔會旋轉。我怎樣才能解決這個問題?即使開始和結束是同一年,JSpinner.DateEditor必須包括年份

import java.awt.GridLayout; 
import java.util.*; 
import javax.swing.*; 

public class T extends JPanel { 

    public T() { 
     super(new GridLayout(2, 2)); 
     init(); 
    } 

    private void init() { 
     Calendar start = GregorianCalendar.getInstance(); 
     Calendar end = GregorianCalendar.getInstance(); 
     start.clear(); 
     end.clear(); 
     start.set(Calendar.YEAR, 2010); 
     end.set(Calendar.YEAR, 2010); 
     end.add(Calendar.HOUR_OF_DAY, 12); 
     SpinnerDateModel m1 = 
       new SpinnerDateModel(start.getTime(), start.getTime(), 
       end.getTime(), Calendar.MILLISECOND); 
     SpinnerDateModel m2 = 
       new SpinnerDateModel(start.getTime(), start.getTime(), 
       end.getTime(), Calendar.MILLISECOND); 
     JSpinner workingSpinner = new JSpinner(m1); 
     workingSpinner.setEditor(
       new JSpinner.DateEditor(workingSpinner, 
       "yyyy HH:mm:ss.SSS")); 
     JSpinner notWorkingSpinner = new JSpinner(m2); 
     notWorkingSpinner.setEditor(
       new JSpinner.DateEditor(notWorkingSpinner, 
       "HH:mm:ss.SSS")); 
     add(new JLabel("Working")); 
     add(workingSpinner); 
     add(new JLabel("!Working")); 
     add(notWorkingSpinner); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    private static void createAndShowGUI() { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new T()); 
     frame.pack(); 
     frame.setVisible(true); 
    } 
} 

回答

5

在JRE源代碼中仔細研究之後,我發現微調器支持文本值而不是真實日期。當你點擊上下旋鈕時,該值將被解析,然後與最小值和最大值進行比較。因爲你的格式沒有一年的日期被解析,年份始終爲1970年,這是從時代開始的年份偏移量0。這會導致微調器在嘗試旋轉時始終返回超出範圍的錯誤。

最快的解決方案是簡單地使用1970年而不是2010年。但是,如果您的初始日期是在1970年底,那麼微調不會讓您的用戶翻到1971年1月(相反它可能會跳回到1970年初)。

另一種解決方案可以適應跨越日曆年邊界的日期。然而,它並不那麼簡單(或漂亮)。在DateFormatter解析日期字符串的JRE中,它使用一個String參數構造函數動態地實例化一個類。該字符串是來自微調器的日期。默認情況下,這個類是Date或者它的一些子類。我們可以讓格式化程序實例化我們自己的Date類,它修復了執行任何日期比較之前的一年。


Date類,增加了一年:

public static class DateThatAddsYear extends Date { 
public DateThatAddsYear(String time) { 
    super(time); 
    Calendar cal = GregorianCalendar.getInstance(); 
    cal.setTime(this); 
    // Jump back to 2010, this needs to be implemented more thoroughly in order 
    // to support dates crossing calendar year boundaries 
    cal.set(Calendar.YEAR, 2010); 
    setTime(cal.getTimeInMillis()); 
} 
} 

手動設置微調,使用我們最新的解決辦法:

JSpinner notWorkingSpinner = new JSpinner(m2); 
JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(notWorkingSpinner); 
DateFormatter formatter = new DateFormatter(format); 
notWorkingSpinner.setEditor(dateEditor); 
dateEditor.getTextField().setFormatterFactory(new DefaultFormatterFactory(formatter)); 
formatter.setValueClass(DateThatAddsYear.class); // Tell it to use a different value class! 

醜陋,但它作品。另外,如果你想在JRE源碼中尋找,我建議你看看InternationalFormatter(DateFormatter的超類)的公共方法stringToValue(String text)

+0

正確,但無法在12:00:00.000停止。就像沒有在模型中設置結束一樣。 – initialZero 2010-10-08 22:20:00

+0

另外,出於某種原因,您的示例也不會向後旋轉。 – initialZero 2010-10-08 23:00:48

+0

更新 - 問題比我原先想象的要深得多。 – Andy 2010-10-08 23:14:32

0

我不知道這是爲什麼不工作,但如果你改變M2的聲明:

SpinnerDateModel M2 =新SpinnerDateModel(); m2.setValue(start.getTime());

它的工作原理。

+0

這是因爲m2將不再需要結束時間。 – initialZero 2010-10-08 21:30:08

+0

該評論是錯誤的,所以我刪除了它。 – 2010-10-08 21:34:29

0

這是一種醜陋的,但我得到它的工作。

這是代碼。我只關心JSpinner的addChangeListener內部的範圍驗證。

import java.awt.GridLayout; 
import java.util.*; 
import javax.swing.*; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class T extends JPanel { 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 

    public T() { 
     super(new GridLayout(2, 2)); 
     init(); 
    } 

    public Calendar end; 
    public JSpinner notWorkingSpinner; 
    private void init() { 
     Calendar start = GregorianCalendar.getInstance(); 
     end = GregorianCalendar.getInstance(); 
     start.clear(); 
     end.clear(); 

     start.set(Calendar.YEAR, 2010); 
     end.set(Calendar.YEAR, 2010); 

     end.add(Calendar.HOUR_OF_DAY, 12); 
     SpinnerDateModel m1 = 
       new SpinnerDateModel(start.getTime(), start.getTime(), 
       end.getTime(), Calendar.MILLISECOND); 

     SpinnerDateModel m2 = new SpinnerDateModel(); 
     m2.setValue(start.getTime()); 

     JSpinner workingSpinner = new JSpinner(m1); 
     workingSpinner.setEditor(
       new JSpinner.DateEditor(workingSpinner, 
       "yyyy HH:mm:ss.SSS")); 
     notWorkingSpinner = new JSpinner(m2); 
     notWorkingSpinner.setEditor(
       new JSpinner.DateEditor(notWorkingSpinner, 
       "HH:mm:ss.SSS")); 

     notWorkingSpinner.addChangeListener(new ChangeListener() { 

      @Override 
     public void stateChanged(ChangeEvent e) { 
      SpinnerModel dateModel = notWorkingSpinner.getModel(); 
      if(dateModel instanceof SpinnerDateModel){ 
       Date check = ((SpinnerDateModel)dateModel).getDate(); 

       Calendar checkCal = GregorianCalendar.getInstance(); 
       checkCal.setTime(check); 
       checkCal.set(Calendar.YEAR, end.get(Calendar.YEAR)); 
       checkCal.set(Calendar.MONTH, end.get(Calendar.MONTH)); 
       checkCal.set(Calendar.DAY_OF_MONTH, end.get(Calendar.DAY_OF_MONTH)); 

       if(checkCal.get(Calendar.HOUR_OF_DAY) == 23){ 
        dateModel.setValue(start.getTime()); 
       } else if(checkCal.getTime().compareTo(end.getTime()) > 0){ 
        dateModel.setValue(end.getTime());    
       } 
      } 
     } 
     }); 

     add(new JLabel("Working")); 
     add(workingSpinner); 
     add(new JLabel("!Working")); 
     add(notWorkingSpinner); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    private static void createAndShowGUI() { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new T()); 
     frame.pack(); 
     frame.setVisible(true); 
    } 
} 
+0

當你向後旋轉時,它不會停止。我想這只是另一個檢查開始。 – initialZero 2010-10-08 23:03:10

+0

是的,我同意。我只是在考慮最高級別的檢查。我們只需要添加一個「start」的檢查。 – 2010-10-08 23:04:31

+0

我修正了答案以適應低端限制。 – 2010-10-08 23:13:14

相關問題