2010-10-06 10 views
6

Mam JSpinner przy użyciu SpinnerDateModel, który ma początek na 1 stycznia 2010 00: 00: 00.000 data końcowa jest 1 stycznia 2010 00:12 : 34,177. Chciałbym, aby mój JSpinner.DateEditor używał formatu HH: mm: ss.SSS, ale spinner nie obraca się z tym formatem. Obraca się tylko, gdy do formatu dodaje się "yyyy". Jak mogę to obejść?JSpinner.DateEditor musi zawierać rok, nawet jeśli początek i koniec jest w tym samym roku

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); 
    } 
} 

Odpowiedz

5

Po dobrym kopaniu w źródle JRE odkryłem, że spinner jest wspierany przez wartość tekstową zamiast prawdziwej daty. Po naciśnięciu przycisku przewijania w górę iw dół wartość jest analizowana, a następnie porównywana z wartościami minimalnymi i maksymalnymi. Ponieważ twój format nie ma roku, daty są parsowane z rokiem zawsze będącym rokiem 1970, który jest rokiem odsunięcia 0 od epoki. Powoduje to, że spinner zawsze zwraca błąd poza zasięgiem, gdy próbujesz go obrócić.

Najszybszym rozwiązaniem jest po prostu użyć jako rok 1970 zamiast 2010. Jednakże, jeśli początkowa data jest na koniec 1970 roku spinner nie pozwoli użytkownikom przewrócić w styczniu 1971 roku (zamiast go może wrócić do początku 1970 roku).

Inne rozwiązanie może pomieścić daty obejmujące granice roku kalendarzowego. Jednak nie jest tak prosty (lub ładny). W środowisku JRE, gdy DateFormatter analizuje ciąg daty, tworzy instancję klasy dynamicznie za pomocą pojedynczego konstruktora parametrów String. Ten ciąg to data od spinnera. Domyślnie ta klasa to Date lub jej podklasa. Możemy sformatować naszą własną klasę Date, która naprawia rok przed wykonaniem jakichkolwiek porównań dat.


Data klasa, która dodaje lat:

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()); 
} 
} 

ręcznie ustawić pokrętła, za pomocą naszego datę Fix:

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! 

brzydki, ale to Prace.

Ponadto, jeśli chcesz zagłębić się w źródle JRE sugeruję, patrząc na publiczną metodę stringToValue(String text) z InternationalFormatter (nadklasa DateFormatter).

+0

Prawidłowo, to się nie kończy o 12: 00: 00.000. Podobnie jak nie ma końca w modelu. – initialZero

+0

Również z jakiegoś powodu twój przykład nie odwraca się wstecz. – initialZero

+0

Zaktualizowany - problem był znacznie głębszy niż początkowo sądziłem. – Andy

0

Nie jestem pewien, dlaczego to nie działa, ale jeśli zmienić deklarację m2 do:

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

to działa.

+0

To dlatego, że m2 nie będzie już wymagać czasu zakończenia. – initialZero

+0

Ten komentarz był nieprawidłowy, więc go usunąłem. –

0

To jest trochę brzydkie, ale mam to działa.

Oto kod. Po prostu zajmuję się walidacją zasięgu wewnątrz addChangeListener dla JSpinnera.

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

Po obróceniu się do tyłu nie zatrzymuje się. Wyobrażam sobie, że to tylko kolejna kontrola, żeby zacząć. – initialZero

+0

Tak, zgadzam się. Właśnie myślałem o sprawdzeniu najwyższego poziomu. Musimy tylko dodać czek na "start". –

+0

Poprawiłem odpowiedź, aby dostosować się również do dolnego limitu. –

Powiązane problemy