# JSpinner, 3 JSpinner aber nur ein SpinnerDateModel



## Tallan (6. Okt 2009)

Hallo zusammen,

ich würde gerne das Datum über einen JSpinner einstellen,
hierfür möchte ich zum ändern des Tags, Monats und Jahres jeweils einen eigenen Spinner verwenden die dann das entsprechende Datum ändern.

Mein Ansatz


```
sdm = new SpinnerDateModel();

        daySpinner = new JSpinner(sdm);
        	daySpinner.setEditor(new DateEditor(daySpinner,"dd"));

 
        monthSpinner = new JSpinner(sdm);
        	monthSpinner.setEditor(new DateEditor(monthSpinner,"MM"));
        	

        yearSpinner = new JSpinner(sdm);
         	yearSpinner.setEditor(new DateEditor(yearSpinner,"yyyy"));
```

funktioniert leider nicht, beim ersten ändern einer Variable ( Tag Monat oder Jahr ) werden die anderne beiden auf 01.01.1970 resetet  bzw eine der 3 wird entsprechend hochgezähl...

Da ich gerne hätte das der Sprung von 31 Tagen auf 1 den Monat hochzählt komme ich wohl um dieses Grundmodel nicht herum.

Weiß jemand wo der fehler liegt?


----------



## dayaftereh (6. Okt 2009)

Hey, erzuge für jeden JSpinner eine eigenes Model! Du nutzt ein Model für 3 Spinner, wenn du jetzt beim ersten Spinner den Wert 3 einstellst, dan bekommt das model den wert 3 und alle JSpinner die auch dieses Model haben auch!


```
sdm = new SpinnerDateModel();

		daySpinner = new JSpinner(sdm);
		daySpinner.setEditor(new DateEditor(daySpinner, "dd"));

		sdm = new SpinnerDateModel();
		monthSpinner = new JSpinner(sdm);
		monthSpinner.setEditor(new DateEditor(monthSpinner, "MM"));

		sdm = new SpinnerDateModel();
		yearSpinner = new JSpinner(sdm);
		yearSpinner.setEditor(new DateEditor(yearSpinner, "yyyy"));
```

Das sollte Funktioniren.


----------



## Tallan (6. Okt 2009)

dayaftereh hat gesagt.:


> Hey, erzuge für jeden JSpinner eine eigenes Model! Du nutzt ein Model für 3 Spinner, wenn du jetzt beim ersten Spinner den Wert 3 einstellst, dan bekommt das model den wert 3 und alle JSpinner die auch dieses Model haben auch!
> 
> 
> ```
> ...



Das hatte ich vorher das Problem ist das es dann 3 unabhängig spinner sind, d.h die Tage im Spinner 1 haben nichts mit denen in 2 zu tun und eben das soll nicht so sein. Ich möchte "ein" Datum ändern mit jeweils einem Spinner für Jahr Monat und Tag


----------



## Ebenius (6. Okt 2009)

Das Problem kenne ich. Eigentlich machst Du nichts falsch, aber es kann so trotzdem so nicht funktionieren. Der DateEditor benutzt ein JFormattedTextField, welches darauf angewiesen ist, per Formatter aus einem String einen Wert erzeugen zu können und vice versa.

Ich würde es so lösen, bzw. habe es schonmal so ähnlich gelöst:


```
/* (@)SpinnerDateFieldModel.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius.swing;

import java.util.Calendar;
import java.util.Date;

import javax.swing.SpinnerDateModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Spinner date model, dedicated to calendar fields.
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 */
public class SpinnerDateFieldModel extends SpinnerDateModel
  implements ChangeListener {

  /** Serial version UID */
  private static final long serialVersionUID = 1L;

  private final SpinnerDateModel calendarMasterModel;

  /** Creates a new {@code SpinnerDateFieldModel}. */
  public SpinnerDateFieldModel(
        SpinnerDateModel calendarMasterModel,
        int calendarField) {
    this.calendarMasterModel = calendarMasterModel;
    calendarMasterModel.addChangeListener(this);
    setCalendarField(calendarField);
  }

  @Override
  public Object getNextValue() {
    calendarMasterModel.setCalendarField(getCalendarField());
    return calendarMasterModel.getNextValue();
  }

  @Override
  public Object getPreviousValue() {
    calendarMasterModel.setCalendarField(getCalendarField());
    return calendarMasterModel.getPreviousValue();
  }

  @Override
  public Object getValue() {
    System.out.println("Date: " + calendarMasterModel.getValue());
    return calendarMasterModel.getValue();
  }

  @Override
  public void setValue(Object value) {
    final Calendar cal = Calendar.getInstance();
    cal.setTime((Date) value);
    final int calendarField = getCalendarField();
    final int fieldValue = cal.get(calendarField);
    cal.setTime(calendarMasterModel.getDate());
    if (cal.get(calendarField) != fieldValue) {
      cal.set(calendarField, fieldValue);
      calendarMasterModel.setValue(cal.getTime());
    }
  }

  public void stateChanged(ChangeEvent e) {
    fireStateChanged();
  }
}
```
Hier eine TestGUI dazu: 
	
	
	
	





```
/* (@)JSpinnerDateTestGUI.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.GridLayout;
import java.util.Calendar;

import javax.swing.*;

import com.ebenius.swing.SpinnerDateFieldModel;

/**
 * Test GUI for spinner date field model.
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 */
public class JSpinnerDateTestGUI {

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    final SpinnerDateModel masterModel = new SpinnerDateModel();

    final JPanel contentPane = new JPanel(new GridLayout(0, 2, 6, 6));
    contentPane.add(new JLabel("Year:"));
    contentPane.add(createSpinner(masterModel, "yyyy", Calendar.YEAR));
    contentPane.add(new JLabel("Month (full):"));
    contentPane.add(createSpinner(masterModel, "MMM", Calendar.MONTH));
    contentPane.add(new JLabel("Month (numeric):"));
    contentPane.add(createSpinner(masterModel, "MM", Calendar.MONTH));
    contentPane.add(new JLabel("Day of Month:"));
    contentPane.add(createSpinner(masterModel, "dd", Calendar.DAY_OF_MONTH));

    final JFrame f = new JFrame("Test Frame: JSpinnerDateTestGUI");
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  private static JSpinner createSpinner(
        SpinnerDateModel masterModel,
        String pattern,
        int calendarField) {
    final JSpinner c =
          new JSpinner(new SpinnerDateFieldModel(masterModel, calendarField));
    c.setEditor(new JSpinner.DateEditor(c, pattern));
    return c;
  }
}
```
Das ganze ist natürlich noch ausgiebig zu testen. 

Happy Hacking!

Nachtrag: 





dayaftereh hat gesagt.:


> Hey, erzuge für jeden JSpinner eine eigenes Model! Du nutzt ein Model für 3 Spinner, wenn du jetzt beim ersten Spinner den Wert 3 einstellst, dan bekommt das model den wert 3 und alle JSpinner die auch dieses Model haben auch!


Der Ansatz, ein Modell für alle Spinner zu benutzen ist eigentlich nicht schlecht. Funktioniert bei anderen Komponenten auch; aber die Spinner sind leider aufgrund Ihrer Formatter etwas zickig.

Ebenius


----------



## Tallan (6. Okt 2009)

Ebenius hat gesagt.:


> Das Problem kenne ich. Eigentlich machst Du nichts falsch, aber es kann so trotzdem so nicht funktionieren. Der DateEditor benutzt ein JFormattedTextField, welches darauf angewiesen ist, per Formatter aus einem String einen Wert erzeugen zu können und vice versa.
> 
> Ich würde es so lösen, bzw. habe es schonmal so ähnlich gelöst:
> 
> ...



Danke für die Mühe leider auch nicht ganz das was ich wollte, da beim Übergang von Tag bzw Monat der Monat bzw das Jahr nicht hochgezählt wird wie beim normalen JSpinner. Das ganze zu  testen und einzeln zu incrementieren wäre zwar eine lösung aber so wie der spinner angelegt ist sollte das auch anders gehen :/


----------



## Ebenius (6. Okt 2009)

Das löse ich auch noch fix. Mal sehen, ob ich's ohne Handstände hinbekomme. 

Ebenius


----------



## Ebenius (6. Okt 2009)

So sollte es funktionieren. Das ist keine besonders schöne Lösung, scheint aber zu funktionieren: 
	
	
	
	





```
/* (@)SpinnerDateFieldModel.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius.swing;

import java.util.Calendar;
import java.util.Date;

import javax.swing.SpinnerDateModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Spinner date model, dedicated to calendar fields.
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 */
public class SpinnerDateFieldModel extends SpinnerDateModel
  implements ChangeListener {

  /** Serial version UID */
  private static final long serialVersionUID = 1L;

  private final SpinnerDateModel calendarMasterModel;
  private transient boolean arrowMode = false;

  /** Creates a new {@code SpinnerDateFieldModel}. */
  public SpinnerDateFieldModel(
        SpinnerDateModel calendarMasterModel,
        int calendarField) {
    this.calendarMasterModel = calendarMasterModel;
    calendarMasterModel.addChangeListener(this);
    setCalendarField(calendarField);
  }

  @Override
  public Object getNextValue() {
    arrowMode = true;
    calendarMasterModel.setCalendarField(getCalendarField());
    return calendarMasterModel.getNextValue();
  }

  @Override
  public Object getPreviousValue() {
    arrowMode = true;
    calendarMasterModel.setCalendarField(getCalendarField());
    return calendarMasterModel.getPreviousValue();
  }

  @Override
  public Object getValue() {
    return calendarMasterModel.getValue();
  }

  @Override
  public void setValue(Object value) {
    if (arrowMode) {
      calendarMasterModel.setValue(value);
      arrowMode = false;
    } else {
      final Calendar cal = Calendar.getInstance();
      cal.setTime((Date) value);
      final int calendarField = getCalendarField();
      final int fieldValue = cal.get(calendarField);
      cal.setTime(calendarMasterModel.getDate());
      if (cal.get(calendarField) != fieldValue) {
        cal.set(calendarField, fieldValue);
        calendarMasterModel.setValue(cal.getTime());
      }
    }
  }

  public void stateChanged(ChangeEvent e) {
    fireStateChanged();
  }
}
```
Ebenius


----------



## Tallan (6. Okt 2009)

klasse danke!


----------

