JAVA编写的日历


日历程序

(www.Jojoo.net)  2002-1-8 (请双击自动滚屏观看,单击停止,再击..)


该 Java 程序可以显示 1582 年以后任一月的日历。用户可以在一个文本框里

  输入年份,通过下拉框选择月份,然后点击“新日历”按纽,就可以显示那个

  月的日历。可以通过在 HTML 文件里加入下面的语句,调用该程序,

  <applet code>="Calendar.class" width=421 height=481></applet>

  该程序假定在一个 421x481 象素的表面上绘制日历

  语言: Java 平台: Unix, Windows

************************************************************************/

import java.applet.Applet;

import java.awt.*;

import java.util.Date;

public class Calendar extends Applet

{

static final int YTOP = 90;   /* 日历上方的空白 */

static final int YHEADER = 30; /* 日期名称行的高度 */

static final int NCELLX = 7;   /* 横行的方格数 */

static final int CELLSIZE = 60; /* 方格的大小 */

static final int MARGIN = 8;   /* 数字距方格上方和右方的空白 */

static final int FEBRUARY = 1; /* 闰年的特殊月份 */

// 日历上方的控件.

Label yearLabel = new Label("Year:");

TextField yearTextField = new TextField("1996", 5);

Label monthLabel = new Label("Month:");

Choice monthChoice = new Choice();

Button newCalButton = new Button("New Calendar");

// 当前年份和月份的日期对象.

Date now = new Date();

// 日历上方的控件的字体.

Font smallArialFont = new Font("Arial", Font.PLAIN, 15);

// 日历上方年月标题的字体.

Font largeArialFont = new Font("Arial", Font.BOLD, 30);

String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",

         "Thursday", "Friday", "Saturday"};

String months[] = {"January", "February", "March", "April",

           "May", "June", "July", "August", "September",

           "October", "November", "December"};

int DaysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

// 用户输入的年和月.

int userMonth;

int userYear;

public void init()

/*

   功能: 获取当前的年份和月份,初始化控件.

   注意: 程序启动时,自动调用.

*/

  {

  setBackground(Color.white);

  // 初始话月份和年份为当前值.

  userMonth = now.getMonth();

  userYear = now.getYear() + 1900;

  // "Year:" 标签.

  yearLabel.setFont(smallArialFont);

  add(yearLabel);

  // 输入年份的文本区.

  yearTextField.setFont(smallArialFont);

  yearTextField.setText(String.valueOf(userYear));

  add(yearTextField);

  // "Month:" 标签.

  monthLabel.setFont(smallArialFont);

  add(monthLabel);

  // 输入月份的组合框.

  monthChoice.setFont(smallArialFont);

  for (int i = 0; i < 12; i++)

   monthChoice.addItem(months[i]);

  monthChoice.select(userMonth);

  add(monthChoice);

  // "新日历" 按纽.

  newCalButton.setFont(smallArialFont);

  add(newCalButton);

  } // 初始化

public void paint(Graphics g)

/*

   功能: 根据全局变量 userMonth 和 userYear 绘制日历.

   注意: 当界面需要重画时会自动调用,用户点击"新日历" 按纽,也会触发重画功能.

*/

  {

  FontMetrics fm;   /* 获取字体信息 */

  int fontAscent;   /* 字符高度 */

  int dayPos;     /* 日期字符串竖直方向的位置 */

  int xSize, ySize; /* 日历的大小 (单元格) */

  int numRows;    /* 行数 (4, 5, 6) */

  int xNum, yNum;   /* number position at top right of cells */

  int numDays;    /* 该月的天数 */

  String dayStr;   /* 一周中星期字符串 */

  int marg;     /* margin of month string baseline from cell table */

  String caption;   /* 上方中心的月份 */

  // 获取字体信息.

  fm = g.getFontMetrics();

  fontAscent = fm.getAscent();

  dayPos = YTOP + (YHEADER + fontAscent) / 2;

  // 日历的宽度 (单元格).

  xSize = NCELLX * CELLSIZE;

  // Header rectangle across top for day names.

  g.drawRect(0, YTOP, xSize, YHEADER);

  // Put days at top of each column, centered.

  for (int i = 0; i < NCELLX; i++)

   g.drawString(days[i], (CELLSIZE-fm.stringWidth(days[i]))/2 + i*CELLSIZE,

         dayPos);

  // 获取该月需要的行数

  numRows = NumberRowsNeeded(userYear, userMonth);

  // 表格的竖直线.

  ySize = numRows * CELLSIZE;

  for (int i = 0; i <= xSize; i += CELLSIZE)

   g.drawLine(i, YTOP + YHEADER, i, YTOP + YHEADER + ySize);

  // 表格的水平线.

  for (int i = 0, j = YTOP + YHEADER; i <= numRows; i++, j += CELLSIZE)

   g.drawLine(0, j, xSize, j);

  // 初始数字的位置(右上角单元).

  xNum = (CalcFirstOfMonth(userYear, userMonth) + 1) * CELLSIZE - MARGIN;

  yNum = YTOP + YHEADER + MARGIN + fontAscent;

  // 获取该月的天数, 如果是闰年的二月, 加一天.

  numDays = DaysInMonth[userMonth] +

       ((IsLeapYear(userYear) && (userMonth == FEBRUARY)) ? 1 : 0);

  // 在每个表格的右上角显示数字.

  for (int day = 1; day <= numDays; day++)

   {

   dayStr = String.valueOf(day);

   g.drawString(dayStr, xNum - fm.stringWidth(dayStr), yNum);

   xNum += CELLSIZE;

   if (xNum > xSize)

    {

    xNum = CELLSIZE - MARGIN;

    yNum += CELLSIZE;

    } // if

   } // for

  // 设置年月标题为大字体.

  g.setFont(largeArialFont);

  // 获取字体信息 (当前为大字体).

  fm = g.getFontMetrics();

  // 设置标题在竖直方向的空白.

  marg = 2 * fm.getDescent();

  // 设置标题为月份, 并在中间位置.

  caption = months[userMonth] + " " + String.valueOf(userYear);

  g.drawString(caption, (xSize-fm.stringWidth(caption))/2, YTOP - marg);

  } // 绘制

public boolean action(Event e, Object o)

/*

   功能: 刷新年月的全局变量, 当用户点击按纽时绘制.

*/

  {

  int userYearInt;

  if (e.target instanceof Button)

   {

   if ("New Calendar".equals((String)o))

    {

    // 从组合框中选择月份.

    userMonth = monthChoice.getSelectedIndex();

    // 从文本框获取年份.

    userYearInt = Integer.parseInt(yearTextField.getText(), 10);

    if (userYearInt > 1581)

     userYear = userYearInt;

    // 调用 paint() 绘制新日历.

    repaint();

    return true;

    }

   }

  return false;

  }

int NumberRowsNeeded(int year, int month)

/*

   功能: 计算日历需要的行数.

   输入: year = 给出的 1582 年以后的年份.

      month = 0 为一月, 1 为二月, 依次类推.

   输出: 行数: 5 或 6, 只有当二月有28天, 同时一号为星期天时, 只需要4行.

*/

  {

  int firstDay;   /* 该月的第一天的星期 */

  int numCells;   /* 该月需要的表格数 */

  /* 年份应为 1582 年以后. */

  if (year < 1582) return (-1);

  /* 去除无效的月份. */

  if ((month < 0) || (month > 11)) return (-1);

  /* 获取该月的第一天. */

  firstDay = CalcFirstOfMonth(year, month);

  /* 如果是闰年的二月, 第一天是星期天, 返回 4 行. */

  if ((month == FEBRUARY) && (firstDay == 0) && !IsLeapYear(year))

   return (4);

  /* 需要的表格数 = 第一行的空表格 + 该月的天数. */

  numCells = firstDay + DaysInMonth[month];

  /* 闰年需要为2月29日增加一格 */

  if ((month == FEBRUARY) && (IsLeapYear(year))) numCells++;

  /* 小于等于35格为5行,更多则为6行. */

  return ((numCells <= 35) ? 5 : 6);

  }

int CalcFirstOfMonth(int year, int month)

/*

   功能: 计算该月第一天是星期几.

   输入: year = 给出的 1582 年以后的年份.

      month = 0 为一月, 1 为二月, 依次类推.

   输出: 该月第一天的星期: 0 = 星期天, 1 = 星期一, 依次类推.

*/

  {

  int firstDay;   /* 该年1月1日的星期,然后是该月第一天的星期 */

  int i;       /* 月份的循环变量 */

  /* 年份应为 1582 年以后. */

  if (year < 1582) return (-1);

  /* 去除无效的月份. */

  if ((month < 0) || (month > 11)) return (-1);

  /* 获取该年1月1日的星期 */

  firstDay = CalcJanuaryFirst(year);

  /* 计算该月第一天是该年中的第几天. */

  for (i = 0; i < month; i++)

   firstDay += DaysInMonth[i];

  /* 闰年二月份后的月份加一天 */

  if ((month > FEBRUARY) && IsLeapYear(year)) firstDay++;

  /* 转换为星期 */

  return (firstDay % 7);

  }

boolean IsLeapYear(int year)

/*

   功能: 判断是否是闰年.

   输入: year = 给出的 1582 年以后的年份.

   输出: TRUE 是闰年, FALSE 不是.

*/

  {

  /* 能被100整除, 不能被400整除的年份, 不是闰年.

   * 能被100整除, 也能被400整除的年份, 是闰年.*/

  if ((year % 100) == 0) return((year % 400) == 0);

  /* 不能被100整除, 能被4整除的年份是闰年. */

  return ((year % 4) == 0);

  }

int CalcJanuaryFirst(int year)

/*

   功能: 计算该年1月1日的星期.

   输入: year = 给出的 1582 年以后的年份.

   输出: 1月1日的星期: 0 = 星期天, 1 = 星期一, 依次类推.

   注意: 1582 年 1 月 1 日是星期五; 平年加1 , 闰年加2.

*/

  {

  /* 年份应为 1582 年以后. */

  if (year < 1582) return (-1);

  /* 始于01-01-1582 星期五; 平年加1 , 闰年加2. */

  return ((5 + (year - 1582) + CalcLeapYears(year)) % 7);

  }

int CalcLeapYears(int year)

/*

   功能: 计算自 1582 年以后的闰年数.

   输入: year = 给出的 1582 年以后的年份.

   输出: 自 1582 年以后的闰年数. 如果早于 1582 年, 返回 -1 .

   注意: 如果给出的年份是闰年, 计算结果不包括它.

      能被100整除, 不能被400整除的年份, 不是闰年.

      能被100整除, 也能被400整除的年份, 是闰年.

      不能被100整除, 能被4整除的年份是闰年.

*/

  {

  int leapYears;   /* 返回的闰年数 */

  int hundreds;   /* 能被100整除的年数 */

  int fourHundreds; /* 能被400整除的年数 */

  /* 年份应为 1582 年以后. */

  if (year < 1582) return (-1);

  /* 能被4整除的年数 */

  leapYears = (year - 1581) / 4;

  /* 计算能被100整除的年数; 然后从闰年数中除去*/

  hundreds = (year - 1501) / 100;

  leapYears -= hundreds;

  /* 闰年数中加上能被400整除的年数 */

  fourHundreds = (year - 1201) / 400;

  leapYears += fourHundreds;

  return (leapYears);

  }

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值