また、前章ではCreateWindowEx関数を用いてコントロールを作成しましたが 今回はVC++のリソースエジタを利用してコントロールを作成します。 また、ダイアログボックスに簡単なメニューを付けます。
ダイアログボックスのメニューで「文字色」を選択すると
左のようなサブメニューが出現します。
ここから、「青」を選択すると・・
1日から月末までの日付の色が青色に変わります。
このほかに、タイトルバーの色などいろいろな個所の色を
変える事ができます。
まず、リソース・エディタで左の図のようなダイアログ・テンプレートを
作ります。この時「OK」「キャンセル」ボタンが少し上のほうに寄っている
ことに注意して下さい。これは、あとからメニューが挿入されて
コントロール全体が下方に移動されるからです。DTPCは、ツールバーの
「コントロール」の中の「日時指定」を選択します。
そして、「ボタン」を作るのと同じ要領で矩形の位置・大きさを
決めます。このコントロールのプロパティの「書式」の中から
「長い形式の日付」「短い形式の日付」「時間」などを選択します。
左の図では日付のコントロールのIDはIDC_DATETIMEPICKER1、右の時間の コントロールのIDはIDC_DATETIMEPICKER2にしてあります。
次に青、赤、緑のメニューアイテムのビットマップを用意します。
これは、"BLUE", "RED", "GREEN"という名前にしておきます。
さて、これだけの準備ができればあとは、前章とほとんど同じ 要領でプログラムを作ることができます。
ビットマップを持つメニューの作り方はすでに 第42章でやりました。 さて、第42章ではCreateMenuやCreatePopupMenu関数で 空のメニューを作っておいてAppendMenuでメニュー項目を追加していきました。 ところが、AppendMenu関数で追加していきました。ところが、このAppendMenu 関数は現在ではInsertMenuItem関数に取って代わられました。 互換性のため、まだ、AppendMenu関数は使えますが将来も使える保証はありません。
hMenuはメニュー項目を挿入するメニューのハンドルを指定します。BOOL WINAPI InsertMenuItem( HMENU hMenu, UINT uItem, BOOL fByPosition, LPMENUITEMINFO lpmii );
uItemはメニュー項目または位置を指定します。この項目の前に新しい項目が挿入されます。
fByPositionにFALSEを指定するとuItemはメニュー項目のID、 FALSE意外を指定すると位置になります。
lpmiiには、MENUITEMINFO構造体へのポインタを指定します。 これは、次のように定義されています。
cbSizeには、この構造体の大きさを指定します。typedef struct tagMENUITEMINFO { UINT cbSize; UINT fMask; UINT fType; UINT fState; UINT wID; HMENU hSubMenu; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; DWORD dwItemData; LPTSTR dwTypeData; UINT cch; } MENUITEMINFO, FAR *LPMENUITEMINFO;
fMaskには、セットするメンバーを指定します。これは次のうちの
1つまたはそれ以上の組み合わせとなります。
値 | 意味 |
---|---|
MIIM_CHECKMARKS | hbmpCheckedとhbmpUncheckedメンバをセットします。 |
MIIM_DATA | dwItemDataメンバをセットします。 |
MIIM_ID | wIDメンバをセットします。 |
MIIM_STATE | fStateメンバをセットします。 |
MIIM_SUBMENU | hSubMenuメンバをセットします。 |
MIIM_TYPE | fTypeおよびdwTypeDataをセットします。 |
fTypeにはメニュー項目のタイプを指定します。次の1つまたはそれ以上の組み合わせです。
値 | 意味 |
---|---|
MFT_BITMAP | ビットマップを使ってメニュー項目を表示します。 dwTypeDataメンバの下位ワード値がビットマップハンドルになります。 cchメンバは無視されます。 |
MFT_MENUBARBREAK | メニュー項目を新しい列に置きます。 ドロップダウンメニュー、サブメニュー、ショートカットメニューの 時は区切り線が入ります。 |
MFT_MENUBREAK | メニュー項目を新しい列に置きます。 区切り線は入りません。 |
MFT_OWNERDRAW | オーナードローをする時指定します。 dwTypeDataメンバにはアプリケーション定義の32ビット値が入ります。 |
MFT_RADIOCHECK | hbmpCheckedメンバがNULLの時 ラジオボタンを使ってチェックされます。 |
MFT_RIGHTJUSTIFY | メニュー項目が右揃えになります。 |
MFT_RIGHTORDER | アラビア語とかヘブライ語の時指定。 |
MFT_SEPARATOR | 区切り線。 dwTypeDataとcchメンバは無視されます。 |
MFT_STRING | メニュー項目に文字列を使います。 dwTypeDataに文字列へのポインタを指定します。 cchには文字列の長さを指定します。 |
fStateには、メニュー項目の状態を指定します。
値 | 意味 |
---|---|
MFS_CHECKED | メニュー項目にチェックをつけます。 |
MFS_DEFAULT | そのメニュー項目がデフォルトであることを指定します。 |
MFS_DISABLED | メニュー項目を選択不能にします。 |
MFS_ENABLED | メニュー項目を選択可能にします。 |
MFS_GRAYED | メニュー項目を灰色にして選択不能にします。 |
MFS_HILITE | メニュー項目をハイライトします。 |
MFS_UNCHECKED | メニュー項目からチェックをはずします。 |
MFS_UNHILITE | メニュー項目のハイライトをやめます。 |
wID はメニューアイテムのIDを指定します。
hSubMenuは、メニュー項目に関連付けられたサブメニューのハンドルを指定します。 メニュー項目がサブメニューを持たない時はNULLを指定します。
hbmpChecked には、チェックマークのビットマップハンドルを指定します。 NULLの時はデフォルトのマークが使われます。
hbmpUncheckedはチェックがはずされた時のビットマップのハンドルを 指定します。NULLの時はビットマップは使われません。
dwItemDataはメニュー項目に関連したアプリケーション定義の値です。
dwTypeDataはメニュー項目の内容です。fMaskにMIIM_TYPEが指定された時のみ有効です。
cchはMFT_STRINGタイプのメニュー項目についての情報を受け取る時の メニュー項目のテキストの長さです。このメンバはMIIM_TYPEフラグがセットされている時のみ 使われます。他の場合は0です。
では、プログラムを見てみましょう。
今回はDialogのリソース・スクリプトにDTPが組み込まれていることに注意して下さい。// newctl02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END MENUITEM "入力(&T)", IDM_INPUT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 159, 65 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "日付・時刻入力" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,25,50,14 PUSHBUTTON "キャンセル",IDCANCEL,102,25,50,14 CONTROL "DateTimePicker1",IDC_DATETIMEPICKER1,"SysDateTimePick32", DTS_RIGHTALIGN | DTS_LONGDATEFORMAT | WS_TABSTOP,7,7,67, 14 CONTROL "DateTimePicker2",IDC_DATETIMEPICKER2,"SysDateTimePick32", DTS_RIGHTALIGN | DTS_UPDOWN | WS_TABSTOP | 0x8,77,7,75, 14 END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // BLUE BITMAP DISCARDABLE "blue.bmp" RED BITMAP DISCARDABLE "red.bmp" GREEN BITMAP DISCARDABLE "green.bmp"
ダイアログボックスに付けるメニューは、アプリケーション側で 作る為reource.hにIDが反映されません。それで、自分でdefineしています。// newctl02.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #include "resource.h" #define IDM_RED 100 #define IDM_GREEN 101 #define IDM_BLUE 102 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void SetMenuBMP(HWND); char szClassName[] = "newctl02"; //ウィンドウクラス HINSTANCE hInst; char szTime[256] = ""; char szDate[256] = "";
このへんは、いつもと変わりません。int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるPicker Ctrl", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 300, //幅 140, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
プロシージャ部分も前回と同じです。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HDC hdc; PAINTSTRUCT ps; INITCOMMONCONTROLSEX ic; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_INPUT: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } break; case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_DATE_CLASSES; InitCommonControlsEx(&ic); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 10, 10, szDate, strlen(szDate)); TextOut(hdc, 10, 50, szTime, strlen(szTime)); EndPaint(hWnd, &ps); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
ダイアログのプローシージャです。メニューからIDM_RED, IDM_GREEN, IDM_BLUEが 選択されたらそれぞれの色をcrTextClrにコピーしておきます。 そして、DateTime_SetMonthCalColorマクロで色を設定します。さて、ここで注意すべこことは まだ色の設定が行われていない時crTextClrはstaticな変数なので0(黒)になっています。 これがデフォルトの色となります。一度設定した色はダイアログを閉じても次回 ダイアログを開いた時有効になります。LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hDate, hTime, hParent; static COLORREF crTextClr; LPSTR lpstrDateFormat = "yy'年'MM'月'dd'日('ddd')'"; LPSTR lpstrTimeFormat = "tthh'時'mm'分'ss'秒'"; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: GetWindowText(hTime, szTime, sizeof(szTime)); GetWindowText(hDate, szDate, sizeof(szDate)); InvalidateRect(hParent, NULL, TRUE); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; case IDM_BLUE: crTextClr = RGB(0, 0, 255); DateTime_SetMonthCalColor(hDate, MCSC_TEXT, crTextClr); break; case IDM_RED: crTextClr = RGB(255, 0, 0); DateTime_SetMonthCalColor(hDate, MCSC_TEXT, crTextClr); break; case IDM_GREEN: crTextClr = RGB(0, 255, 0); DateTime_SetMonthCalColor(hDate, MCSC_TEXT, crTextClr); break; } break; case WM_INITDIALOG: SetMenuBMP(hDlg); hDate = GetDlgItem(hDlg, IDC_DATETIMEPICKER1); hTime = GetDlgItem(hDlg, IDC_DATETIMEPICKER2); SendMessage(hDate, DTM_SETFORMAT, 0, (LPARAM)lpstrDateFormat); SendMessage(hTime, DTM_SETFORMAT, 0, (LPARAM)lpstrTimeFormat); hParent = GetParent(hDlg); DateTime_SetMonthCalColor(hDate, MCSC_TEXT, crTextClr); return TRUE; } return FALSE; }
DTPコントロールのカレンダーの色を変えるマクロです。 DTM_SETMCCOLOR メッセージを送っても同様のことが行えます。COLORREF DateTime_SetMonthCalColor( HWND hwndDP, int iColor, COLORREF clr );
hwndDPはDTPコントロールのハンドルです。
iColorは色をセットする部分を指定します。次の中から1つを指定します。
値 | 意味 |
---|---|
MCSC_BACKGROUND | 月の間の背景色とあるが意味不明 |
MCSC_MONTHBK | カレンダー部分の背景色 |
MCSC_TEXT | その月のテキスト(1日から月末まで) |
MCSC_TITLEBK | タイトルの背景色、および曜日の色 |
MCSC_TITLETEXT | タイトルのテキストの色 |
MCSC_TRAILINGTEXT | 前月およびよく月の日にちの色 |
clrには色を指定します。
WM_INITDIALOGが来たら、GetDlgItem関数でDTPコントロールのハンドルを 取得します。
ダイアログボックスにビットマップのメニュー項目を持つメニューを 付ける関数です。InsertMenuItem関数とMENUITEMINFO構造体の使い方に注意して下さい。void SetMenuBMP(HWND hDlg) { HMENU hMenu, hSubMenu; HBITMAP hBMPG, hBMPR, hBMPB; MENUITEMINFO mi; hBMPG = LoadBitmap(hInst, "GREEN"); hBMPR = LoadBitmap(hInst, "RED"); hBMPB = LoadBitmap(hInst, "BLUE"); hMenu = CreateMenu(); hSubMenu = CreatePopupMenu(); memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_TYPE | MIIM_SUBMENU; mi.fType = MFT_STRING; mi.fState = MFS_ENABLED; mi.wID = 0; mi.hSubMenu = hSubMenu; mi.dwTypeData = "文字色(&C)"; InsertMenuItem(hMenu, 0, TRUE, &mi); mi.fMask = MIIM_TYPE | MIIM_ID; mi.fType = MFT_BITMAP; mi.wID = IDM_GREEN; mi.dwTypeData = (LPTSTR)hBMPG; InsertMenuItem(hSubMenu, 0, TRUE, &mi); mi.wID = IDM_RED; mi.dwTypeData = (LPSTR)hBMPR; InsertMenuItem(hSubMenu, 1, TRUE, &mi); mi.wID = IDM_BLUE; mi.dwTypeData = (LPSTR)hBMPB; InsertMenuItem(hSubMenu, 2, TRUE, &mi); SetMenu(hDlg, hMenu); return; }
Update 28/Feb/1999 By Y.Kumei