万年カレンダを表示

ウインドウの右隅に万年カレンダを表示します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. 新規プロジェクト(Calender)を作成して下さい。
    以下の説明を元にプログラムを作成して下さい。
  2. 大の月と小の月のテーブルです。
    MT[] が1月から12月の月ごとの日数で、MTBL[] がその累積です。
    2月は28日で格納します。
    MT[] と MTBL[] はどちらかを定義すれば、片方は計算できます。
    st はプログラムが起動された日付を取得する領域です。
    yobi は月初の曜日を求める領域です。
        int         MTBL[12]=  { 0,31,59,90,120,151,181,212,243,273,304,334 };
        int         MT[12];
        SYSTEMTIME  st;
        int         yobi;
        
  3. プログラムが起動されると GetLocalTime() で本日の日付を取得します。
    SetYobi() 関数で月初の曜日を求めます。
        switch(msg)
        {   case WM_CREATE:
                GetLocalTime(&st);
                SetYobi();
                break;
        
  4. 月初の曜日を求める SetYobi() 関数です。
        //★ 月初の曜日を設定
        void  SetYobi()
        {
            //月初の曜日を計算
            //月のテーブル(MTBL[], MT[])を設定
            //うるう年は MT[] の2月を29日にする
        }
        
  5. 月初の曜日を求めるために 2000年1月1日からの通算日数を計算します。
    2000年から100年間は、4で割り切れる年はうるう年です。
        //★ 西暦2000年1月1日(土)からの通算日数を調べる関数
        long  days(int yy, int mm, int dd)
        {
            //1年を365日として通算日数を計算
            //うるう年と、その年の年初からの日数を加える
            return 通算日数;
        }
        
  6. 月初の曜日とその月の日数が決まればカレンダを表示するのは簡単でしょう。
    文字の表示は TextOut() を使います。
    可変ピッチフォントで表示位置がずれるときは、固定ピッチフォントを使って下さい。
    フォントの設定は、ペンやブラシと同じ要領です。
        HFONT   hFontOld;
        hFontOld= (HFONT)SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
        
    ウインドウを右隅に表示するときは SystemParametersInfo() で画面全体のサイズを求めてウインドウ位置を設定します。
        RECT        rc;
        SystemParametersInfo(SPI_GETWORKAREA,0,&rc,sizeof(rc));
        

【演習】

欲張らずに手順を踏んでプログラムを完成させて下さい。
  1. プログラムが起動された日付を表示する。
  2. 月初の曜日を計算する。
  3. カレンダの数字を並べる。
  4. 見出しと色を設定して、体裁を整える。
  5. 画面の右下に表示する。
  6. メニュー設定で「年,月」を指定できるようにする。

【全ソースコード】

/*★ 万年 Calender   Version 1.0  前田 稔 ★*/
#define     NAME    "Calender"
#include    <windows.h>
#include    "resource.h"

HINSTANCE   g_hInst;
HWND        g_hWnd;
char        WTBL[][4]= { "日","月","火","水","木","金","土" };
int         MTBL[12]=  { 0,31,59,90,120,151,181,212,243,273,304,334 };
int         MT[12];
int         yobi,today,wYear,wMonth,wDay;
SYSTEMTIME  st;
char        buf[64];

//★ 西暦2000年1月1日(土)からの通算日数を調べる関数
long  days(int yy, int mm, int dd)
{   long    w,yw;
    yw= yy-2000;
    if (yw<0)   return 0L;
    w=  yw*365L;            //年*365
    w+= (yw/4L + MTBL[mm-1] + dd);
    if (mm<3 && yw%4==0)  w--;
    return w;
}

//★ 月初の曜日の設定と日付の編集
void  SetYobi()
{   int     i;
    //月初の曜日を計算
    today= days(st.wYear,st.wMonth,1);
    yobi= (today+6)%7L;
    wsprintf(buf,"%d年%d月%d日 %s曜日 【1日(%s)】",
                 st.wYear,st.wMonth,st.wDay,WTBL[st.wDayOfWeek],WTBL[yobi]);
    //月のテーブルを設定
    for(i=0; i<11; i++) MT[i]= MTBL[i+1]-MTBL[i];
    MT[11]= 31;
    if (st.wMonth%4==0) MT[1]++;
}

//★ Calender を表示する
void  Disp(HDC hdc)
{   int     i,wk,xp;
    HFONT   hFontOld;

    hFontOld= (HFONT)SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
    wsprintf(buf,"%d 年  %d 月",st.wYear,st.wMonth);
    TextOut(hdc,60,0,buf,strlen(buf));
    TextOut(hdc,10,20,"日  月  火  水  木  金  土",26);
    SetTextColor(hdc,RGB(255,0,0));
    TextOut(hdc,10,20,"日",2);
    SetTextColor(hdc,RGB(0,0,255));
    TextOut(hdc,202,20,"土",2);
    for(i=0; i<MT[st.wMonth-1]; i++)
    {   wk= yobi+i;
        wsprintf(buf," %2d",i+1);
        SetTextColor(hdc,RGB(0,0,0));
        xp= wk%7;
        if (xp==0)  SetTextColor(hdc,RGB(255,0,0));
        if (xp==6)  SetTextColor(hdc,RGB(0,0,255));
        if (wDay==i+1 && wYear==st.wYear && wMonth==st.wMonth)
                    SetTextColor(hdc,RGB(0,200,0));
        TextOut(hdc,xp*32,(wk/7)*20+40,buf,strlen(buf));
    }
    SetTextColor(hdc,RGB(0,0,0));
    SelectObject(hdc,hFontOld);
}

// Function Prototype
LRESULT  CALLBACK   WndProc(HWND, UINT, WPARAM, LPARAM);
int      APIENTRY   WinMain(HINSTANCE, HINSTANCE, LPSTR, int);

LRESULT CALLBACK DlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{   int     wk;

    switch(msg)
    {   case WM_INITDIALOG:
            SetDlgItemText(hDlg,IDC_EDIT1,"2000");
            break;
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {   case IDOK:
                    GetDlgItemText(hDlg,IDC_EDIT1,buf,sizeof(buf));
                    wk= atoi(buf);
                    if (wk<2000)    break;
                    st.wYear= wk;
                    GetDlgItemText(hDlg,IDC_EDIT2,buf,sizeof(buf));
                    st.wMonth= atoi(buf);
                    SetYobi();
                    InvalidateRect(g_hWnd,NULL,TRUE);
                    EndDialog(hDlg,TRUE);
                    return TRUE;
                case IDCANCEL:
                    PostMessage(hDlg,WM_CLOSE,0,0);
                    return TRUE;
            }
            break;
        case WM_CLOSE:
            EndDialog(hDlg,TRUE); 
            return TRUE;
    }
    return FALSE;
}

//★ CALLBACK 関数
LRESULT  CALLBACK  WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{   PAINTSTRUCT ps;
    HDC         hdc;

    switch(msg)
    {   case WM_CREATE:
            GetLocalTime(&st);
            wYear= st.wYear;
            wMonth= st.wMonth;
            wDay= st.wDay;
            SetYobi();
            break;
        case WM_PAINT:
            hdc= BeginPaint(hWnd, &ps);
            Disp(hdc);
            EndPaint(hWnd, &ps);
            break;
        case WM_COMMAND:
            switch(LOWORD(wParam)) 
            {   case IDM_DATE:
                    DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)DlgProc);
                    break;
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd,msg,wParam,lParam);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0L;
    }
    return  DefWindowProc(hWnd,msg,wParam,lParam);
}

//★ Windows Main 関数
int APIENTRY  WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)
{   MSG         msg;
    RECT        rc;

    g_hInst= hInst;
    SystemParametersInfo(SPI_GETWORKAREA,0,&rc,sizeof(rc));
    WNDCLASS wc = { CS_CLASSDC,WndProc,0L,0L,hInst,
                    LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1)),
                    LoadCursor(NULL,IDC_ARROW),
                    (HBRUSH)GetStockObject(WHITE_BRUSH),
                    MAKEINTRESOURCE(IDR_MENU1),NAME };
    if (RegisterClass(&wc)==0)    return FALSE;
    g_hWnd= CreateWindow(NAME,NAME,WS_OVERLAPPEDWINDOW,
            rc.right-240,rc.bottom-220,240,220,
            NULL,NULL,hInst,NULL);
    if (!g_hWnd)  return FALSE;

    ShowWindow(g_hWnd,nCmdShow);
    UpdateWindow(g_hWnd);
    SetFocus(g_hWnd);
    while (GetMessage(&msg,NULL,0,0))
    {   TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return S_OK;                    //return 0
}

超初心者のプログラム入門(Win32API C++)