もう少しまともなカレンダー〜スケジュール管理ソフトをS!アプリで作ってみよう(その9)

前回から、大分、間が空いてしまった。Blogに書くのも、結構時間がかかるので、とにかくソフトの完成だけを目指そうかと思っていた。でも、検索エンジンにも引っかかるようなので、続けていこうと思う。まさか間違いの指摘をされるとは...

さすがに、月単位でカレンダーを表示するだけでは、スケジュールの管理はできないので、日にちを選択・移動できるようにする。

月表示、週表示、2週間表示とでは、日にちの並ぶ方向を変えるつもりでいる。だから、同じ下方向のキーがおされても、月表示では1週間後に移動となるが、2週間表示では1日後になると言うように違いが出てくる。なので、キーの処理は、MonthlyCalenderクラスで行っている。


package com.ettem.scheduler;

import java.util.*;
import javax.microedition.lcdui.*;

/**
* 月間カレンダーを表示する。
*/
public class MonthlyCalendar {
private Calendar dateToDisplay; // この日のカレンダーを表示する。
public int x, y; // カレンダーの開始位置。
public int width, height; // カレンダーの幅と高さ。
private Font font; // フォント。

/**
* 月間カレンダーを構築します。
* @param canvas カレンダーを描画するCanvas
* @param x カレンダーの開始X座標
* @param y カレンダーの開始Y座標
* @param width カレンダーの幅
* @param height カレンダーの高さ
* @param dateToDisplay カレンダーで描画すべき日
*/
public MonthlyCalendar(Canvas canvas, int x, int y, int width, int height,
Calendar dateToDisplay) {
this.dateToDisplay = Calendar.getInstance();
this.dateToDisplay.setTime(dateToDisplay.getTime());
this.x = x;
this.y = y;

// 指定されたX座標、幅では画面からはみ出る場合は右端までにする。
if (x + width > canvas.getWidth()) {
width = canvas.getWidth() - x;
}
this.width = width;

// 必要な画面の高さを求める(選択日の行 + 曜日カラムヘッダ + 6週間分)
font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL);
int needHeight = font.getHeight() * 2 + ((font.getHeight() * 5) / 2) * 6;

// 指定された高さが、必要以下の場合は強制的に高くする。
if (height < needHeight) {
height = needHeight;
}

// 指定されたY座標、高さでは画面からはみ出る場合は下端までにする。
if ( y + height > canvas.getHeight()) {
height = canvas.getHeight() - y;
}
this.height = height;
}

/**
* 描画すべき日付を設定
* @param date
*/
public void setDate(Calendar date) {
dateToDisplay.setTime(date.getTime());
}

/**
* Canvasのアクションに応じて、移動先の日付を返す。
* @param keyCode Canvasで押されたkeyCode
*/
public Calendar getMovedDateByKeyCode(int keyCode) {
Calendar dateTmp = Calendar.getInstance();
dateTmp.setTime(dateToDisplay.getTime());

switch (keyCode) {
case Canvas.KEY_STAR:
dateTmp.set(Calendar.MONTH,
dateToDisplay.get(Calendar.MONTH) - 1);
dateTmp.getTime();
if (dateTmp.get(Calendar.MONTH) ==
dateToDisplay.get(Calendar.MONTH)) {
dateTmp.set(Calendar.DAY_OF_MONTH, 0);
}
break;
case Canvas.KEY_POUND:
dateTmp.set(Calendar.MONTH,
dateToDisplay.get(Calendar.MONTH) + 1);
if (dateTmp.get(Calendar.MONTH) >
dateToDisplay.get(Calendar.MONTH) + 1) {
dateTmp.set(Calendar.DAY_OF_MONTH, 0);
}
break;
}

return dateTmp;
}

/**
* Canvasのアクションに応じて、移動先の日付を返す。
* @param keyCode Canvasで押されたキーのアクション
*/
public Calendar getMovedDateByAction(int action) {
Calendar dateTmp = Calendar.getInstance();
dateTmp.setTime(dateToDisplay.getTime());

switch (action) {
case Canvas.UP:
dateTmp.set(Calendar.DAY_OF_MONTH,
dateToDisplay.get(Calendar.DAY_OF_MONTH) - 7);
break;
case Canvas.DOWN:
dateTmp.set(Calendar.DAY_OF_MONTH,
dateToDisplay.get(Calendar.DAY_OF_MONTH) + 7);
break;
case Canvas.LEFT:
dateTmp.set(Calendar.DAY_OF_MONTH,
dateToDisplay.get(Calendar.DAY_OF_MONTH) - 1);
break;
case Canvas.RIGHT:
dateTmp.set(Calendar.DAY_OF_MONTH,
dateToDisplay.get(Calendar.DAY_OF_MONTH) + 1);
break;
}

return dateTmp;
}

public void paint(Graphics graphics) {
Calendar firstInMonth = Calendar.getInstance();
Calendar lastInMonth = Calendar.getInstance();
int baseLine = y;

// 描画領域のクリア
graphics.setColor(0xFFFFFF);
graphics.fillRect(x, y, x + width, y + height);

// 選択日の月の最初と最後の日を求める。
firstInMonth.setTime(dateToDisplay.getTime());
firstInMonth.set(Calendar.DAY_OF_MONTH, 1);

lastInMonth.setTime(dateToDisplay.getTime());
lastInMonth.set(Calendar.MONTH, lastInMonth.get(Calendar.MONTH) + 1);
lastInMonth.set(Calendar.DAY_OF_MONTH, 0); // 日にちを0にすると、前の月の最終日となる。

graphics.setColor(0x000000);
Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL);
graphics.setFont(font);

/*
* 選択された日付を表示
*/
String dateStr = dateToDisplay.get(Calendar.YEAR) + "/"
+ String.valueOf(dateToDisplay.get(Calendar.MONTH) + 1) + "/"
+ dateToDisplay.get(Calendar.DAY_OF_MONTH);
graphics.drawString(dateStr,
(x + (x + width)) / 2, baseLine, Graphics.TOP | Graphics.HCENTER);
baseLine += font.getHeight();

/*
* 曜日のカラムを作成
*/
int dayOfWeekWidth = width / 8;
int dayOfWeekStringOffset = dayOfWeekWidth / 2;
String[] dayOfWeek = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

for (int i = 0; i < 7; i++) {
graphics.drawString(dayOfWeek[i],
x + (i + 1) * dayOfWeekWidth + dayOfWeekStringOffset, baseLine,
Graphics.TOP | Graphics.HCENTER);
}
baseLine += font.getHeight();

/*
* 日付欄を作成
*/
int cellWidth = width / 8;
int cellHeight = (font.getHeight() * 5) / 2;
int cellInsets = 2;
Calendar dateTmp = Calendar.getInstance();
dateTmp.setTime(firstInMonth.getTime());

drawDateTable:
for (int i = 0, x = 0, y = 0; i < 6; i++) {
for (int j = 1; j < 8; j++) {
if (i >= 5 && j >= 3) {
break drawDateTable;
}

// 枠線を描画
x = this.x + j * cellWidth;
y = this.y + baseLine + i * cellHeight;
graphics.drawRect(x, y, cellWidth, cellHeight);

// 日付を描画

// 1日よりも前の部分、月末より後の部分は表示しない。
if (i == 0 && j < firstInMonth.get(Calendar.DAY_OF_WEEK)
|| dateTmp.after(lastInMonth)) {
continue;
}

graphics.drawString(String.valueOf(dateTmp.get(Calendar.DAY_OF_MONTH)),
x + cellInsets, y + cellInsets,
Graphics.TOP|Graphics.LEFT);
dateTmp.set(Calendar.DAY_OF_MONTH, dateTmp.get(Calendar.DAY_OF_MONTH) + 1);

}
}
}
}

MonthlyCalendarで大部分を処理しているので、MainCanvasは短くなる。


package com.ettem.scheduler;

import java.util.Calendar;
import javax.microedition.lcdui.*;

/**
* メインの画面
* カレンダーを表示する。
* (その日の予定、ToDoも表示する予定)
*/
public class MainCanvas extends Canvas {
private Calendar now;
private Calendar dateToDisplay;
private MonthlyCalendar calendar;

public MainCanvas() {
now = Calendar.getInstance();
dateToDisplay = Calendar.getInstance();
dateToDisplay.setTime(now.getTime());
calendar = new MonthlyCalendar(this, 0, 0, getWidth(), 0, dateToDisplay);
}

protected void paint(Graphics graphics) {
calendar.paint(graphics);
}

protected void keyPressed(int keyCode) {
int action = getGameAction(keyCode);

// action == 0 で判定できるかと思ったけど、
// KEY_START、KEY_POUNDはGameActionが割当てられていた。
if (keyCode == KEY_STAR
|| keyCode == KEY_POUND) {
dateToDisplay.setTime(calendar.getMovedDateByKeyCode(keyCode).getTime());
} else {
dateToDisplay.setTime(calendar.getMovedDateByAction(action).getTime());
}
calendar.setDate(dateToDisplay);

repaint();
}
}