第295章 ヘッダーコントロールとリストビューの組み合わせ5


今回はヘッダーコントロールとリストビューのフォントを自由に変更できるようにしてみます。



左の図のように、フォントを変えることにより縦書き表示にすることもできます。



フォント選択のダイアログボックスです。ChooseFont関数で出てくるダイアログボックスを 自分でテンプレートを作って簡略化しています。ChooseFont関数について忘れてしまった人は 第38章を参照してください。



では、プログラムを見てみましょう。

// header06.rc の一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "新規作成(&N)...", IDM_NEW MENUITEM "開く(&O)...", IDM_OPEN MENUITEM SEPARATOR MENUITEM "名前を付けて保存(&A)...", IDM_SAVEAS MENUITEM "上書き保存(&S)", IDM_SAVE, GRAYED MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "データの追加(&A)...", IDM_ADDITEM MENUITEM "データの削除(&D)...", IDM_DELITEM MENUITEM "データ編集(&I)...", IDM_EDITITEM END POPUP "オプション(&O)" BEGIN POPUP "フォントの変更(&F)" BEGIN MENUITEM "ヘッダコントロール(&H)...", IDM_HEADERFONT MENUITEM "リストビュー(&L)...", IDM_LISTFONT END END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // ADDITEM DIALOG DISCARDABLE 0, 0, 143, 123 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "データの追加" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,36,7,97,12,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,36,29,97,12,ES_AUTOHSCROLL EDITTEXT IDC_EDIT3,36,47,29,12,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_EDIT4,36,63,99,33,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN DEFPUSHBUTTON "OK",IDOK,7,102,50,14 PUSHBUTTON "キャンセル",IDCANCEL,86,102,50,14 LTEXT "氏名:",IDC_STATIC,7,7,16,8 LTEXT "住所:",IDC_STATIC,7,29,16,8 LTEXT "年齢:",IDC_STATIC,7,49,16,8 LTEXT "備考:",IDC_STATIC,7,65,16,8 END MYFONTDLG DIALOG DISCARDABLE 0, 0, 115, 93 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "フォント選択" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,73,44,14 PUSHBUTTON "キャンセル",IDCANCEL,61,73,44,14 COMBOBOX 1136,7,7,73,72,CBS_SIMPLE | CBS_SORT | WS_VSCROLL | WS_TABSTOP COMBOBOX 1138,85,7,19,71,CBS_SIMPLE | CBS_SORT | WS_VSCROLL | WS_TABSTOP END

MYFONTDLGはフォント指定のダイアログボックスです。 MYFONTDLGのコンボボックスのIDを直接1136, 1138と数値で指定していることに 注意してください。フォント名を指定するコンボボックスはcmb1、サイズを 指定するコンボボックスはcmb3と決められています。これは、dlgs.hでは0x0470, 0x0472と定義されています。これを10進数に直すと1136, 1138となります。

// header06.cpp #ifndef STRICT #define STRICT #endif #define ID_HEADER 100 #define ID_LIST 101 #define NO_OF_SUBITEM 4 #define UP 1 #define DOWN 2 #define MAX_FILE_SIZE (1024 * 64) #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <imm.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int CALLBACK MyCompProc(LPARAM, LPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MySetItem(HWND); BOOL MySetListItem(HWND); LRESULT CALLBACK AddItemProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK EditItemProc(HWND, UINT, WPARAM, LPARAM); BOOL MySaveAs(HWND, HWND); BOOL MySave(HWND, HWND); BOOL MyOpen(HWND, HWND); LRESULT CALLBACK MyListProc(HWND, UINT,WPARAM, LPARAM); BOOL MyChangeFont(HWND, HFONT *); char szClassName[] = "header06"; //ウィンドウクラス HINSTANCE hInst; int sortsubno[NO_OF_SUBITEM]; HWND g_hList; int no_of_item, param_of_item; int no_of_edititem; //編集するアイテム BOOL bChanged; //内容が変更されたかどうか static char szFile[MAX_PATH], szTitle[MAX_PATH]; char szWinTitle[MAX_PATH], *szOrgTitle = "猫でもわかるヘッダコントロール [%s]"; WNDPROC OrgListProc; //元々のリストビューのプロシージャ

MyChangeFont関数のプロトタイプ宣言が増えました。

WinMain, InitApp, InitInstanceの各関数に変更はありません。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, nHeaderh, nItem; static HWND hHeader, hList, hEdit; INITCOMMONCONTROLSEX ic; RECT rc; HDLAYOUT hdl; WINDOWPOS wpos; NMHDR *lpnmhdr; NMHEADER *lpnh; char szBuf[256], szName[64]; DWORD dwExStyle; HMENU hMenu; SCROLLINFO si; static HFONT hHeaderF, hListF; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&ic); hHeader = CreateWindow(WC_HEADER, "", WS_CHILD | WS_BORDER | HDS_BUTTONS, 0, 0, 0, 0, hWnd, (HMENU)ID_HEADER, hInst, NULL); hList = CreateWindow(WC_LISTVIEW, "", WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_EDITLABELS, 0, 0, 0, 0, hWnd, (HMENU)ID_LIST, hInst, NULL); //元々のリストビューのプロシージャを保存 OrgListProc = (WNDPROC)GetWindowLong(hList, GWL_WNDPROC); //リストビューのサブクラス化 SetWindowLong(hList, GWL_WNDPROC, (LONG)MyListProc); SetWindowLong(hList, GWL_USERDATA, (LONG)hHeader); dwExStyle = ListView_GetExtendedListViewStyle(hList); dwExStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES; ListView_SetExtendedListViewStyle(hList, dwExStyle); g_hList = hList; MySetItem(hHeader); MySetListItem(hList); break; case WM_INITMENU: hMenu = GetMenu(hWnd); if (bChanged && strcmp(szTitle, "") != 0) EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_ENABLED); else EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_GRAYED); break; case WM_SIZE: rc.left = 0; rc.top = 0; rc.right = LOWORD(lp); rc.bottom = HIWORD(lp); hdl.pwpos = &wpos; hdl.prc = &rc; SendMessage(hHeader, HDM_LAYOUT, 0, (LPARAM)&hdl); SetWindowPos(hHeader, wpos.hwndInsertAfter, wpos.x, wpos.y, wpos.cx, wpos.cy, wpos.flags | SWP_SHOWWINDOW); GetWindowRect(hHeader, &rc); nHeaderh = rc.bottom - rc.top; MoveWindow(hList, 0, nHeaderh, LOWORD(lp), HIWORD(lp) - nHeaderh, TRUE); memset(&si, 0, sizeof(SCROLLINFO)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; GetScrollInfo(hList, SB_HORZ, &si); ListView_Scroll(hList, -si.nPos, 0); break; case WM_NOTIFY: lpnmhdr = (NMHDR *)lp; if (lpnmhdr->hwndFrom == hHeader) { switch (lpnmhdr->code) { case HDN_ITEMCLICK: lpnh = (NMHEADER *)lp; if (sortsubno[lpnh->iItem] == UP) sortsubno[lpnh->iItem] = DOWN; else sortsubno[lpnh->iItem] = UP; ListView_SortItems(hList, MyCompProc, lpnh->iItem); bChanged = TRUE; break; case HDN_ENDTRACK: lpnh = (NMHEADER *)lp; ListView_SetColumnWidth(hList, lpnh->iItem, lpnh->pitem->cxy); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } } else { return (DefWindowProc(hWnd, msg, wp, lp)); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_ADDITEM: no_of_item = ListView_GetItemCount(hList); if (DialogBox(hInst, "ADDITEM", hWnd, (DLGPROC)AddItemProc) == IDOK) bChanged = TRUE; param_of_item++; break; case IDM_DELITEM: while (1) { nItem = ListView_GetNextItem(hList, -1, LVNI_ALL | LVNI_SELECTED); if (nItem == -1) break; ListView_GetItemText(hList, nItem, 0, szName, sizeof(szName)); wsprintf(szBuf, "「%s」の項目を削除してよろしいですか", szName); id = MessageBox(hWnd, szBuf, "項目の削除", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { ListView_DeleteItem(hList, nItem); bChanged = TRUE; } else //削除しない場合は選択状態を解除しないとまずい(いつまでも聞かれる) ListView_SetItemState(hList, nItem, 0, LVIS_SELECTED); } break; case IDM_EDITITEM: while (1) { nItem = ListView_GetNextItem(hList, -1, LVNI_ALL | LVNI_SELECTED); if (nItem == -1) break; no_of_edititem = nItem; //編集するアイテムNOをプロシージャからもわかるようにする if (DialogBox(hInst, "ADDITEM", hWnd, (DLGPROC)EditItemProc) == IDOK) bChanged = TRUE; } break; case IDM_SAVEAS: MySaveAs(hWnd, hList); wsprintf(szWinTitle, szOrgTitle, szTitle); SetWindowText(hWnd, szWinTitle); break; case IDM_SAVE: MySave(hWnd, hList); break; case IDM_NEW: if (bChanged == TRUE) { id = MessageBox(hWnd, "現在のデータに変更があります。破棄してもよろしいですか", "注意", MB_YESNO | MB_ICONQUESTION); if (id == IDNO) break; } ListView_DeleteAllItems(hList); wsprintf(szWinTitle, szOrgTitle, ""); SetWindowText(hWnd, szWinTitle); break; case IDM_OPEN: if (bChanged == TRUE) { id = MessageBox(hWnd, "現在のデータに変更があります。破棄してもよろしいですか", "注意", MB_YESNO | MB_ICONQUESTION); if (id == IDNO) break; } ListView_DeleteAllItems(hList); wsprintf(szWinTitle, szOrgTitle, ""); SetWindowText(hWnd, szWinTitle); if (MyOpen(hWnd, hList)) { wsprintf(szWinTitle, szOrgTitle, szTitle); SetWindowText(hWnd, szWinTitle); } break; case IDM_HEADERFONT: MyChangeFont(hHeader, &hHeaderF); break; case IDM_LISTFONT: MyChangeFont(hList, &hListF); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } break; case WM_CLOSE: if (bChanged == TRUE) { id = MessageBox(hWnd, "データに変更があります。破棄してもよろしいですか", "注意", MB_YESNO | MB_ICONQUESTION); if (id == IDNO) break; } id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (hHeaderF) DeleteObject(hHeaderF); if (hListF) DeleteObject(hListF); //サブクラス化の解除 SetWindowLong(hList, GWL_WNDPROC, (LONG)OrgListProc); DestroyWindow(hList); DestroyWindow(hHeader); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メインウィンドウのプロシージャです。

メニューからIDM_HEADERFONTや、IDM_LISTFONTが選択されたらMyChangeFont関数を 呼び出します。

プログラム終了時に、hHeaderFやhListFが有効であればDeleteObjectしておきます。

MySetItem, MySetListItem, MyCompProc, AddItemProc, EditItemProc, MySaveAs, MySave, MyOpen, MyListProcの各関数に変更はありません。

BOOL MyChangeFont(HWND hWnd, HFONT *lphFont) { static LOGFONT lf; CHOOSEFONT cf; RECT rc; HWND hParent; memset(&cf, 0, sizeof(CHOOSEFONT)); cf.lStructSize = sizeof(CHOOSEFONT); cf.hwndOwner = hWnd; cf.hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); cf.lpLogFont = &lf; cf.Flags = CF_ENABLETEMPLATE | CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT; cf.nFontType = SCREEN_FONTTYPE; cf.lpTemplateName = "MYFONTDLG"; if (ChooseFont(&cf) == 0) return FALSE; if (*lphFont) DeleteObject(*lphFont); *lphFont = CreateFontIndirect(&lf); SendMessage(hWnd, WM_SETFONT, (WPARAM)*lphFont, MAKELPARAM(TRUE, 0)); hParent = GetParent(hWnd); GetWindowRect(hParent, &rc); MoveWindow(hParent, rc.left, rc.top, rc.right - rc.left + 1, rc.bottom - rc.top, FALSE); MoveWindow(hParent, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); return TRUE; }

CHOOSEFONT構造体のFlagsメンバにCF_ENABLETEMPLATEをセットしておくと自作のテンプレートを 使うことができます。

ChooseFont関数を実行してユーザーがキャンセルボタンを押したときは何もせずFALSEを返します。

ユーザーがOKボタンを押した(新しいフォントが選択された)時は、まず今までのフォントハンドルを 破棄してからWM_SETFONTメッセージでフォントをセットします。なおWM_SETFONTメッセージについては 第194章を参照してください。

さて、フォントを指定したあと指定したフォントに合うようにヘッダコントロールやリストビューの 大きさを調整する必要があります。これは、InvalidateRect関数で無効領域を発生させても だめです。フォントは選択したものに変わるのですが、コントロールの大きさが対応しません。 WM_SIZEメッセージが親ウィンドウに行くとここで、調整しているので好都合です。 ここでは、無精をしてMoveWindow関数で親の横幅を1ピクセルだけ大きくして、そのあとすぐに 元に戻しています。これで、親にWM_SIZEメッセージが送られコントロールの調整ができます。

今回は特に目新しいものはありませんでした。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 10/Dec/2000 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。