views:

1122

answers:

4

i want to create a field that looks like this ....can any one tell me how this could be done which field could i use where in i can select values by using the trackball/wheel or in case of storm i could slide...

alt text

+1  A: 

There is a new field introduced in the 5.0 API called SpinBoxFieldManager. For your specific case, there is also a DateTimePicker just for dates/times. For operating systems prior to 5.0, you'll need to create your own custom controls.

Marc Novakowski
thanks but i am aware of the fields...but i need a date picker that is consistent for all the platforms...from 4.2 to 4.7...and hence i wanted to be able to use the above date picker(posted by coldice) on 4.7...as it is working on all the previous ones..only on the touch screen it fails..
Kaddy
+4  A: 

It could be simple Label or Bitmap Field extention, with navigation event handling.

You will need to hold String array with values which will be changed in circle on horizontal navigation.
If such custom Field is focused, draw Up and Down arrays.

So, there will be one such Field for DayOfWeek, one for Month, one for DayOfMonth, one for Year.

Place them all in HorizontalFieldManager, which will be placed in PopupScreen, on popup close geather all values and compose Date value (may be passed over FieldChangeListener)

UPDATE

Storm support

On devices with wheel its easy to implement save-and-close functionality on navigation click, but in Storm that would be a problem (dialog will be closed on each field focus action). To solve this, OK and Cancel buttons added.

Also, touchEvent added to handle proper value change using touch click.

You may keep different implementations for RIM OS <= 4.6 and RIM OS >= 4.7, and replace them on build task.

Source

alt textalt text
alt text

class DatePickerDialog extends PopupScreen implements FieldChangeListener {

    DatePickerField mDatePicker;
    ButtonField mOKButton;
    ButtonField mCancelButton;

    public DatePickerDialog(Date date) {
     super(new VerticalFieldManager(), PopupScreen.DEFAULT_CLOSE);
     add(mDatePicker = new DatePickerField(date));

     // comment on RIM OS < 4.7
     addButtons();
    }

    private void addButtons() {
     HorizontalFieldManager hfm = new HorizontalFieldManager(FIELD_HCENTER);
     add(hfm);
     mOKButton = new ButtonField("OK", ButtonField.CONSUME_CLICK);
     mOKButton.setChangeListener(this);
     hfm.add(mOKButton);
     mCancelButton = new ButtonField("Cancel", ButtonField.CONSUME_CLICK);
     mCancelButton.setChangeListener(this);
     hfm.add(mCancelButton);
    }

    public void setDate(Date dateValue) {
     mDatePicker.setDate(dateValue);
    }

    public Date getDate() {
     return mDatePicker.getDate();
    }

    public DatePickerDialog() {
     this(Calendar.getInstance().getTime());
    }

    // comment on RIM OS < 4.7
    public void fieldChanged(Field field, int context) {
     if (mOKButton == field) {
      getChangeListener().fieldChanged(this, 0);
      close();
     } else if (mCancelButton == field) {
      close();
     }
    }

    // comment on RIM OS > 4.6
    // protected boolean navigationClick(int status, int time) {
    // getChangeListener().fieldChanged(this, 0);
    // close();
    // return super.navigationClick(status, time);
    // }

    class DatePickerField extends HorizontalFieldManager implements
      FieldChangeListener {
     private String[] daysOfWeek = new String[] { "Sunday", "Monday",
       "Tuesday", "Wednesday", "Thursday", "Friday", 
       "Saturday" };
     private String[] months = new String[] { "Jan", "Feb", "Mar", "Apr",
       "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", 
       "Dec" };
     private int mDayOfMonth = 10;
     private int mMonth = 1;
     private int mYear = 2009;

     private StrTimeField mDayOfWeekField;
     private StrTimeField mMonthField;
     private NumTimeField mDayOfMonthField;
     private NumTimeField mYearField;
     Calendar calendar = Calendar.getInstance();

     public DatePickerField(Date date) {
      calendar.setTime(date);
      mYear = calendar.get(Calendar.YEAR);
      // Calendar.JANUARY == 0, so +1 value
      mMonth = calendar.get(Calendar.MONTH);
      mDayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
      int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
      // think it's better to disable Day Of Week edit
      mDayOfWeekField = new StrTimeField(daysOfWeek, dayOfWeek - 1,
        NON_FOCUSABLE);
      mDayOfWeekField.setChangeListener(this);
      add(mDayOfWeekField);
      mMonthField = new StrTimeField(months, mMonth);
      mMonthField.setChangeListener(this);
      add(mMonthField);
      mDayOfMonthField = new NumTimeField(mDayOfMonth, 1, 31);
      mDayOfMonthField.setChangeListener(this);
      add(mDayOfMonthField);
      mYearField = new NumTimeField(mYear, 1900, 2012);
      mYearField.setChangeListener(this);
      add(mYearField);
     }

     public void fieldChanged(Field field, int context) {
      mDayOfMonth = mDayOfMonthField.getValue();
      calendar.set(calendar.DAY_OF_MONTH, mDayOfMonth);
      mMonth = mMonthField.getValue();
      calendar.set(calendar.MONTH, mMonth);
      mYear = mYearField.getValue();
      calendar.set(calendar.YEAR, mYear);
      int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
      mDayOfWeekField.setIndex(dayOfWeek);
     }

     public Date getDate() {
      return calendar.getTime();
     }

     public void setDate(Date date) {
      calendar.setTime(date);
      mYear = calendar.get(Calendar.YEAR);
      mMonth = calendar.get(Calendar.MONTH);
      mDayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
      int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
      mDayOfWeekField.setIndex(dayOfWeek - 1);
      mMonthField.setIndex(mMonth);
      mDayOfMonthField.setValue(mDayOfMonth);
      mYearField.setValue(mYear);
     }

     abstract class TimeField extends LabelField {
      int mWidth = 0;

      public TimeField() {
       super("", FOCUSABLE);
      }

      public TimeField(long style) {
       super("", style);
      }

      protected abstract void switchValue(int step);

      protected boolean navigationMovement(int dx, int dy, 
        int status, int time) {
          if (Math.abs(dy) > Math.abs(dx)) {
              switchValue(-dy);
       return true;
          } else
              return super.navigationMovement(dx, dy, status, time);
      }

      boolean prepared = false;

      protected void onFocus(int direction) {
       prepared = false;
       super.onFocus(direction);
      }

      protected void onUnfocus() {
       invalidate();
       super.onUnfocus();
      }

      // comment on RIM OS < 4.7
      protected boolean touchEvent(TouchEvent msg) {
       if (isFocus() && msg.getEvent() == TouchEvent.CLICK) {
        if (!prepared) {
         prepared = true;
        } else {
         int y = msg.getY(1);
         int cy = getTop() + (getHeight() >> 1);
         switchValue((y > cy) ? -1 : 1);
        }
       }
       return false;
      }

      public int getPreferredWidth() {
       return mWidth;
      }

      public int getPreferredHeight() {
       return super.getPreferredHeight() + 24;
      }

      protected void layout(int width, int height) {
       super.layout(width, height);
       setExtent(getPreferredWidth(), getPreferredHeight());
      }

      protected void paint(Graphics graphics) {
       String text = getText();
       Font font = getFont();
       int x = (getPreferredWidth() 
        - font.getAdvance(text)) >> 1;
       int y = (getPreferredHeight() - font.getHeight()) >> 1;
       graphics.drawText(text, x, y);
       if (isFocus()) {
        graphics.setColor(Color.WHITE);
        int xc = (getPreferredWidth() >> 1);
        int y1 = 10, y2 = 0, x2 = xc - 9, x1 = xc + 9;

        int[] xPts = new int[] { x1, x2, xc };
        int[] yPts = new int[] { y1, y1, y2 };
        graphics.drawFilledPath(xPts, yPts, 
            null, null);

        y2 = getPreferredHeight();
        y1 = y2 - 10;

        yPts = new int[] { y1, y1, y2 };
        graphics.drawFilledPath(xPts, yPts, 
            null, null);
       }
      }

      public abstract int getValue();
     }

     class StrTimeField extends TimeField {
      String[] mValues;
      int mIndex;

      public StrTimeField(String[] values) {
       this(values, 0);
      }

      public StrTimeField(String[] values, int value) {
       this(values, value, FOCUSABLE);
      }

      public StrTimeField(String[] values, int value, long style) {
       super(style);
       mValues = values;
       setIndex(value);
       Font font = getFont();
       for (int i = 0; i < mValues.length; i++) {
        int width = font.getAdvance(mValues[i]);
        mWidth = Math.max(mWidth, width);
       }
       mWidth += 10;
      }

      protected void switchValue(int step) {
       int index = mIndex + step;
       if (index < 0 || index >= mValues.length)
        index += ((index > 0) ? -1 : 1) 
            * mValues.length;
       setIndex(index);
      }

      private void setIndex(int index) {
       if (index >= 0 && index < mValues.length) {
        mIndex = index;
        setText(mValues[mIndex]);
       }
      }

      public int getValue() {
       return mIndex;
      }

     }

     class NumTimeField extends TimeField {
      int mValue;
      int mMinValue;
      int mMaxValue;

      public NumTimeField(int val, int minVal, int maxVal) {
       this(val, minVal, maxVal, FOCUSABLE);
      }

      public NumTimeField(int val, int minVal, int maxVal,
        long style) {
       super(style);
       mValue = val;
       mMinValue = minVal;
       mMaxValue = maxVal;

       setText(String.valueOf(mValue));
       int maxDig = String.valueOf(mMaxValue).length();
       String test = "";
       for (int i = 0; i < maxDig; i++)
        test += "0";
       mWidth = getFont().getAdvance(test);
       mWidth += 10;
      }

      protected void switchValue(int step) {
       int value = mValue + step;
       if (value > mMaxValue)
        value = value - (mMaxValue - mMinValue + 1);
       if (value < mMinValue)
        value = value + (mMaxValue - mMinValue + 1);
       setValue(value);
      }

      private void setValue(int value) {
       mValue = value;
       setText(String.valueOf(mValue));
      }

      public int getValue() {
       return mValue;
      }
     }
    }
}
Max Gontar
i was running your code it runs perfectly on all versions except 4.7 storm...in storm the navigation movements does not seem to map...when ever i click on the field it goes to be background..could you suggest something that could be done to make it work on 4.7 as well as this is one of my target platforms...
Kaddy
Also had to make minor changes to make it run on 4.2 likeinstead of getVisualState() method used isFocus()and instead of MathUtilities.pow(10, maxDig) implemented the pow method on my won...int pow( int x, int y) /*we define the power method with base x and power y (i.e., x^y)*/{ int z = x; for( int i = 1; i < y; i++ )z *= x; return z;}
Kaddy
I was thinking if the triangles that we are drawing could also act as buttons..then it would also work on storm..,by directly clicking on the triangles user can increase or decrease the date..but i am not sure if this could be done...and how..?
Kaddy
thanks for comments!
Max Gontar
thanks for the update and for adding the storm support..but i was looking in for something consistent for all the platforms...something that i could compile on 4.2.1 and run on all the higher platforms..including the 4.7..but struggling with it..
Kaddy
A: 

can any one tell me how to make it work on the storm..

Kaddy
Suggestions please..
Kaddy
A: 

This is a comment to Max's post (not enough credits to post a comment so answer will do)

If you are using his post be advised that the calendar is being hard coded for every month having 31 days.

mDayOfMonthField = new NumTimeField(mDayOfMonth, 1, 31);

Instead of 31 you should use:

net.rim.device.api.util.DateTimeUtilities.getNumberOfDaysInMonth(month, year);

Landi