エディットコントロールの利用
Windows には組み込みのコントロールライブラリがあります。そのライブラリには、 「ボタン」コントロール、「エディット」コントロール、「リストボックス」コントロールなど、 Windows のユーザーインターフェイスを構成する基本的な要素が含まれています。
今回はこれまで作ってきたプログラムをさらに改造します。クライアント領域に、 「エディット」コントロールを配置することによって、メモ帳のような概観を持つプログラムにします。
図1. メモ帳のようにテキスト文書が編集できる
ただし、今回の範囲ではファイルを開いたり、保存したりはしません。 ファイル操作は次回以降に行います。
エディット コントロール
エディットコントロールは、テキスト文書を編集するための矩形領域のウィンドウです。
エディットコントロールを作成するには、CreateWindow 関数にてウィンドウクラス名として "edit" を指定します。 つまり、「コントロール」と呼ばれていますが、実際にはウィンドウクラス名が "edit" であるウィンドウなのです。
また、CreateWindow 関数を呼ぶ際に、「コントロールスタイル」を指定することによって、 どのようなエディットコントロールにするか、指定することができます。 例えば、垂直スクロールバーをつける (ES_AUTOVSCROLL)、パスワード入力用のウィンドウにする (ES_PASSWORD) 等です。
ウィンドウスタイルの完全なリファレンスは MSDN を見てください。
MSDN Edit Control Styles
エディットコントロールを作成するコードの抜粋は以下です。
HWND g_hEdit = NULL; ... g_hEdit = CreateWindow ( TEXT ("edit"), // "edit" クラスを指定 NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, // コントロールスタイルを指定 0, 0, 0, 0, hwnd, (HMENU) IDM_EDIT, lpCreateStruct->hInstance, NULL) ;
HWND 型の変数 g_hEdit をグローバル変数として定義しています。CreateWindow 関数でエディットコントロールを作成した結果、 ウィンドウハンドルが返るのでそれを保持しています。
エディットコントロールへの操作は、g_hEdit で指し示されるウィンドウへウィンドウメッセージを送信することによって行います。 このため、g_hEdit を取っておくと都合が良いのです。また、ウィンドウのサイズや位置を変える場合にもウィンドウハンドルが必要です。
今回は WM_SIZE のイベントハンドラにて MoveWindow 関数を用いて、 エディットコントロールをメインウィンドウのクライアント領域にぴったりはめ込んでいます。 WM_SIZE イベントのイベントハンドラ Main_OnSize の引数に、クライアント領域のサイズ (cx, cy) が渡されるのでそれを利用できます。
void Main_OnSize( HWND hwnd, UINT state, int cx, int cy ) { MoveWindow ( g_hEdit, 0, 0, cx, cy, TRUE ); }
サンプルプログラムの作成
それでは、コードを書いてみましょう。今回はエディットコントロールを作成して、クライアント領域に配置するだけです。
前回までのコードからの変更箇所は、黄色でハイライトしています。
simple.h はこちらです。
#pragma once #include <windows.h> #define WND_CLASS_NAME TEXT("My_Window") #define IDM_EDIT 1 LRESULT CALLBACK WindowProc( HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam); void Main_OnClose( HWND hwnd ); void Main_OnCommand( HWND hwnd, int id, HWND hwndCtl, UINT codeNotify ); BOOL Main_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct); void Main_OnDestroy( HWND hwnd ); void Main_OnSize( HWND hwnd, UINT state, int cx, int cy );
simple.cpp はこちらです。
#include "simple.h" #include <windowsx.h> #include "resource.h" HWND g_hEdit = NULL; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { HWND hWnd; WNDCLASSEX wcl; TCHAR szTitle[256]; wcl.cbSize = sizeof(WNDCLASSEX); wcl.hInstance = hInstance; wcl.lpszClassName = WND_CLASS_NAME; wcl.lpfnWndProc = WindowProc; wcl.style = NULL; wcl.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP)); wcl.hIconSm = NULL; wcl.hCursor = LoadCursor(NULL, IDC_ARROW); wcl.lpszMenuName = MAKEINTRESOURCE (IDR_MENU_MAIN); wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); if(!RegisterClassEx(&wcl)) { return FALSE; } LoadString ( hInstance, IDS_APP_TITLE, szTitle, sizeof(szTitle)/sizeof(szTitle[0]) ); hWnd = CreateWindowEx( NULL, WND_CLASS_NAME, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if(!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); MSG msg; BOOL bRet; while( ( bRet = GetMessage( &msg, NULL, 0, 0 ) ) != 0) { if (bRet == -1) { break; } else { TranslateMessage ( &msg ); DispatchMessage( &msg ); } } return msg.wParam; } LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { HANDLE_MSG( hwnd, WM_CLOSE, Main_OnClose ); HANDLE_MSG( hwnd, WM_COMMAND, Main_OnCommand ); HANDLE_MSG( hwnd, WM_CREATE, Main_OnCreate ); HANDLE_MSG( hwnd, WM_DESTROY, Main_OnDestroy ); HANDLE_MSG( hwnd, WM_SIZE, Main_OnSize ); default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } void Main_OnClose( HWND hwnd ) { TCHAR szMsg [256]; TCHAR szCaption [256]; LoadString ( GetModuleHandle(NULL), IDS_MSG_QUIT, szMsg, sizeof(szMsg)/sizeof(szMsg[0]) ); LoadString ( GetModuleHandle(NULL), IDS_CAPTION_CONF, szCaption, sizeof(szCaption)/sizeof(szCaption[0]) ); if ( IDYES == MessageBox ( hwnd, szMsg, szCaption, MB_YESNO ) ) { DestroyWindow(hwnd); } } void Main_OnCommand( HWND hwnd, int id, HWND hwndCtl, UINT codeNotify ) { switch( id ) { case IDM_FILE_EXIT: SendMessage ( hwnd, WM_CLOSE, 0, 0 ); break; case IDM_HELP_ABOUT: ::MessageBox ( NULL, TEXT("Hello, About!"), TEXT("About This Program"), MB_OK ); break; } }BOOL Main_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) { g_hEdit = CreateWindow ( TEXT ("edit"), NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0, 0, 0, 0, hwnd, (HMENU) IDM_EDIT, lpCreateStruct->hInstance, NULL) ; UpdateWindow(g_hEdit); if(!g_hEdit) { MessageBox(hwnd, TEXT("CreateWindow Failed."), TEXT("Title"), MB_OK); return FALSE; } return TRUE; }void Main_OnDestroy( HWND hwnd ) { ::PostQuitMessage( 0 ); } void Main_OnSize( HWND hwnd, UINT state, int cx, int cy ) { MoveWindow ( g_hEdit, 0, 0, cx, cy, TRUE ); }
リソースファイル、メイクファイル等は前回までと同じです。
これで図1のような画面ができるはずです。
今回はエディットコントロールを作成して、クライアント領域に配置しました。