这个程序主要优3个.java文件组成,
MyCalendar.java (主要显示Calendar的方格和方格里面的数字,并根据日期确定每个小方格里的数字)
MyCalendarHeader.java (在Calendar的上方显示年和月,并能调整年,月,同时反映到Calendar.java中)
CalendarDemo.java (程序的运行类)
在编写这个程序的时候,主要遇到了如下几个问题:
1. 获得系统当前的时间Calendar.getInstance(); 里面最好加上TimeZone.getTimeZone("GMT+8:00"),要不然显示的日期会是错误的,比如系统时间为19号00:04分的时候,用Calendar.getInstance(); 调用返回的系统日期还是18号。
2. Calendar.MONTH返回的月份是 一月对应0,二月对应1;星期天对应1,星期一对应2,依此类推
//////////////MyCalendar.java////////////////////////
package MyCalendar;

import java.util.Calendar;
import java.util.TimeZone;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CustomItem;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;


public class MyCalendar extends CustomItem implements ItemCommandListener ...{
private final static Command CMD_SELECT = new Command("Select", Command.ITEM,1);
protected Display display;
private int rows = 6; //定义表格行数
private int cols = 7; //定义表格列数
private int dx = 20; //定义表格宽度
private int dy = 20; //定义表格高度
private int currentX = 0; //定义当前的行数
private int currentY = 0; //定义当前的列数
private Calendar cal; //记录当前的日期
private int curyear, curmonth, curday; //存储本机的年月日

private static int[] dayOfMonth = ...{31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31}; //保存非闰年的每个月的天数
private String[][] data = new String[rows][cols]; //存储日历表格中的数字

/**//*测试数据
private String[][] data = {{" 1"," 2"," 3"," 4"," 5"," 6"," 7"},
{" 8"," 9","10","11","12","13","14"},
{"15","16","17","18","19","20","21"},
{"22","23","24","25","26","27","28"},
{"29","30","31"," "," "," "," "},
{" "," "," "," "," "," "," "}
};
*/

public MyCalendar(String title, Display d) ...{
super(title);
display = d;
this.setDefaultCommand(CMD_SELECT);
this.setItemCommandListener(this);
cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8:00"));
curyear = cal.get(Calendar.YEAR);
curmonth = cal.get(Calendar.MONTH);
curday = cal.get(Calendar.DAY_OF_MONTH);
setData(curyear, curmonth, curday);
}


protected int getMinContentWidth() ...{
return (cols * dx) + 1;
}


protected int getMinContentHeight() ...{
return (rows * dy) + 1;
}


protected int getPrefContentWidth(int arg0) ...{
return (cols * dx) + 1;
}


protected int getPrefContentHeight(int arg0) ...{
return (rows * dy) + 1;
}


protected void paint(Graphics g, int w, int h) ...{

for (int i = 0; i <= rows; i++) ...{
g.drawLine(0, i*dy, cols*dx, i*dy);
}

for (int i = 0; i <= cols; i++) ...{
g.drawLine(i*dx, 0, i*dx, rows*dy);
}
int oldColor = g.getColor(); //保存当前颜色
g.setColor(0x00d0d0d0);
//填充灰色方格
g.fillRect((currentX * dx) + 1, (currentY * dy) + 1, dx - 1, dy - 1);
g.setColor(oldColor); //恢复原来颜色
//填写数字

for (int i = 0; i < rows; i++) ...{

for (int j = 0; j < cols; j++) ...{

if (data[i][j] != null) ...{
int oldClipX = g.getClipX();
int oldClipY = g.getClipY();
int oldClipWidth = g.getClipWidth();
int oldClipHeight = g.getClipHeight();
//设置裁减区大小,并填写数字
//注意:必须在setClip的地方写数字,要不然就写不上去的
g.setClip((j*dx) + 1, (i*dy) + 1, dx - 1, dy - 1);
//g.setColor(0x000000ff);
g.drawString(data[i][j], (j*dx) + 5, (i * dy) + 5, Graphics.TOP | Graphics.LEFT);
//恢复画布g的原来信息
g.setClip(oldClipX, oldClipY, oldClipWidth, oldClipHeight);
}
}
}
}
protected boolean traverse(int dir,
int viewportWidth,
int viewportHeight,

int[] visRect_inout) ...{

switch (dir) ...{
case Canvas.DOWN:

if (currentY < (rows - 1)) ...{
currentY++;
repaint(currentX * dx, (currentY - 1) * dy, dx, dy); //把上一次填灰的方块填白
repaint(currentX * dx, currentY * dy, dx, dy); //把当前方块填灰

} else ...{
return false;
}
break;
case Canvas.UP:

if (currentY > 0) ...{
currentY--;
repaint(currentX * dx, (currentY + 1) * dy, dx, dy); //把上一次填灰的方块填白
repaint(currentX * dx, currentY * dy, dx, dy); //把当前方块填灰

} else ...{
return false;
}
break;
case Canvas.LEFT:

if (currentX > 0) ...{
currentX--;
repaint((currentX + 1) * dx, currentY * dy, dx, dy); //把上一次填灰的方块填白
repaint(currentX * dx, currentY * dy, dx, dy); //把当前方块填灰

} else ...{
return false;
}
break;
case Canvas.RIGHT:

if (currentX < (cols - 1)) ...{
currentX++;
repaint((currentX - 1) * dx, currentY * dy, dx, dy); //把上一次填灰的方块填白
repaint(currentX * dx, currentY * dy, dx, dy); //把当前方块填灰

} else ...{
return false;
}
break;
}
visRect_inout[0] = currentX;
visRect_inout[1] = currentY;
visRect_inout[2] = dx;
visRect_inout[3] = dy;
//System.out.println(visRect_inout[0]);
//System.out.println(visRect_inout[1]);
//System.out.println(visRect_inout[2]);
//System.out.println(visRect_inout[3]);
return true;
}
//设置方格中需要显示的数字

public void setText(String text) ...{
data[currentX][currentY] = text;
repaint(currentY * dx, currentX * dy, dx, dy);
}

protected void setData(int year, int month, int day) ...{
//System.out.println(year + "--"+ month + "--"+ day);
//一月对应0,星期天对应1,星期一对应2,依此类推
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DAY_OF_MONTH, 1); //用1是为了获得1号是星期几

int daysofmonth = getDaysOfMonth(year, month); //获得当前月的天数

int whichDay = cal.get(Calendar.DAY_OF_WEEK) - 1; //获得当前月的第一天是星期几(因为已经设置cal为1号)

int number = 1; //为下面的循环记录天数
data[0][0] = "日";
data[0][1] = "一";
data[0][2] = "二";
data[0][3] = "三";
data[0][4] = "四";
data[0][5] = "五";
data[0][6] = "六";

for (int i = 1; i < rows; i++) ...{

for (int j = 0; j < cols; j++) ...{

if (j < whichDay && i == 1) ...{
data[i][j] = "";
continue;
}

if (number <= daysofmonth) ...{
data[i][j] = String.valueOf(number);
number++;
continue;
}
data[i][j] = "";
}
}
//有可能日历五行显示不下,那么最后显示不下的那几天在第一行显示

for (int i = 0; number <= daysofmonth; i++,number++) ...{
data[1][i] = String.valueOf(number);
}
//设置当前日期在方格的位置以便填灰色
cal.set(Calendar.DAY_OF_MONTH,day); //由于刚才把当前天设为1号,现在为了显示当前天再设回来
int daysofweek = cal.get(Calendar.DAY_OF_WEEK); //记录当前天是一周的第几天
currentX = daysofweek - 1;
currentY = (day + whichDay) / 7 ;

if((day + whichDay) % 7 != 0) ...{ //如果不能整除
currentY++;

if (currentY > 5) ...{
currentY = 1;
}
}
}

private int getDaysOfMonth(int year, int month) ...{
if (month != 1) //如果不是2月
return dayOfMonth[month];
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
return 29;
return 28;
}


public void commandAction(Command c, Item i) ...{
}


public void setSelectedDate(int year, int month, int day) ...{
// if (day > getDaysOfMonth(year, month)) {
// day = getDaysOfMonth(year, month);
// }
//防止在调整月份的时候显示当前天会有问题(比如在8月31号就不能跳到9月31号)
day = (day>getDaysOfMonth(year, month))?getDaysOfMonth(year, month):day;
setData(year, month, day);
repaint();
}
}

////////////////MyCalendarHeader.java//////////////////////////
package MyCalendar;

import java.util.Calendar;
import java.util.TimeZone;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.CustomItem;
import javax.microedition.lcdui.Graphics;


public class MyCalendarHeader extends CustomItem ...{
//确定是选了年还是月
private final static int SELECT_YEAR = 0;
private final static int SELECT_MONTH = 1;
private final static int SELECT_NONE = 2;
private int location = SELECT_NONE; //开始默认为什么都没有选中
private Calendar cal;
private MyCalendar myCal;
private int year, month, day;

public MyCalendarHeader(String title, MyCalendar myCal) ...{
super(title);
this.myCal = myCal;
cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8:00"));
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DAY_OF_MONTH);
}


protected int getMinContentWidth() ...{
return 130;
}


protected int getMinContentHeight() ...{
return 40;
}


protected int getPrefContentWidth(int arg0) ...{
return 130;
}


protected int getPrefContentHeight(int arg0) ...{
return 40;
}


protected void paint(Graphics g, int w, int h) ...{
int oldColor = g.getColor();

if (location == SELECT_YEAR) ...{
g.setColor(0x00d0d0d0);
g.fillRect(30, 2, 60, 18);

} else if (location == SELECT_MONTH) ...{
g.setColor(0x00d0d0d0);
g.fillRect(35, 22, 50, 38);
}
g.setColor(oldColor);
//保存裁减区
int oldClipX = g.getClipX();
int oldClipY = g.getClipY();
int oldClipWidth = g.getClipWidth();
int oldClipHeight = g.getClipHeight();
//设置裁减区的大小
g.setClip(30, 2, 100, 18);
g.drawString("<<" + String.valueOf(year) + "年>>", 31, 2, Graphics.LEFT | Graphics.TOP);
g.setClip(35, 22, 100, 38);
g.drawString("<<" + String.valueOf(month) + "月>>", 35, 22, Graphics.LEFT | Graphics.TOP);
//保存原来画布信息
g.setClip(oldClipX, oldClipY, oldClipWidth, oldClipHeight);
}

protected boolean traverse(int dir,
int viewportWidth,
int viewportHeight,

int[] visRect_inout) ...{

switch (dir) ...{
case Canvas.DOWN:

if (location == SELECT_YEAR) ...{
location = SELECT_MONTH;

} else if (location == SELECT_MONTH) ...{
location = SELECT_NONE;
return false;

} else if (location == SELECT_NONE) ...{
location = SELECT_YEAR;
}
repaint();
break;
case Canvas.UP:

if (location == SELECT_YEAR) ...{
location = SELECT_NONE;
return false;

} else if (location == SELECT_MONTH) ...{
location = SELECT_YEAR;

} else if (location == SELECT_NONE) ...{
location = SELECT_MONTH;
}
repaint();
break;
case Canvas.LEFT:

if (location == SELECT_YEAR) ...{
year--;
repaint();
myCal.setSelectedDate(year, month-1, day);
}

if (location == SELECT_MONTH) ...{

if (month > 1) ...{
month--;

} else ...{
month = 12;
}
repaint();
myCal.setSelectedDate(year, month-1, day);
}
break;
case Canvas.RIGHT:

if (location == SELECT_YEAR) ...{
year++;
repaint();
myCal.setSelectedDate(year, month-1, day);
}

if (location == SELECT_MONTH) ...{
month = month % 12 + 1;
repaint();
myCal.setSelectedDate(year, month-1, day);
}
break;
}
return true;
}
}

/////////////////CalendarDemo.java/////////////////////////////
package MyCalendar;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;


public class CalendarDemo extends MIDlet implements CommandListener ...{
private final static Command CMD_EXIT = new Command("Exit", Command.EXIT,1);
private Display display;
private Form mainForm;

public CalendarDemo() ...{
mainForm = new Form("My Calendar");
}


protected void startApp() throws MIDletStateChangeException ...{
display = Display.getDisplay(this);
MyCalendar myCal = new MyCalendar("", display);
mainForm.append(new MyCalendarHeader("", myCal));
mainForm.append(myCal);
mainForm.addCommand(CMD_EXIT);
mainForm.setCommandListener(this);
display.setCurrent(mainForm);
}


protected void pauseApp() ...{
}


protected void destroyApp(boolean arg0) throws MIDletStateChangeException ...{
}


public void commandAction(Command c, Displayable d) ...{

if (c == CMD_EXIT) ...{

try ...{
destroyApp(false);

} catch (MIDletStateChangeException e) ...{
e.printStackTrace();
}
notifyDestroyed();
}

}

}

程序运行效果如下:
