第214章 IPアドレスコントロール


IPアドレスは202.247.23.40などのように4つのフィールドから なっています。前から順にフィールド0、フィールド1、...というように 名前が付けられています。各フィールドには0から255までの 整数が入ります。このIPアドレス専用の入力受付がIPアドレスコントロール です。Comctl32.dllのバージョンが4.71以降で使用可能です。



各フィールドは、数字しか入力することができません。3桁入力すると 自動的に次のフィールドに移動します。そのフィールドが2桁以下しか 必要でないときは右矢印キーで次のフィールドに移動します。



IPアドレスコントロールはCreateWindow(Ex)関数で作るか、 リソースエディタでダイアログボックスのコントロールとして作ります。 前者の場合ウィンドウクラスをWC_IPADDRESSにします。

どちらで作るにしても、コモンコントロールの前準備が必要です。 INITCOMMONCONTROLSEX構造体のdwIccメンバをICC_INTERNET_CLASSES に設定してInitCommonControlsEx関数で初期化します。

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

// ip01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "IPアドレスを入力(&I)", IDM_IP END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 115, 53 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "IPアドレス" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,31,50,14 PUSHBUTTON "キャンセル",IDCANCEL,59,31,50,14 CONTROL "IPAddress1",IDC_IPADDRESS1,"SysIPAddress32",WS_TABSTOP, 19,7,77,13 END

普通のメニューと、ダイアログボックスのリソーススクリプトです。 IPアドレスコントロールの位置大きさはリソースエディタで適当に 決めてください。

// ip01.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "ip01"; //ウィンドウクラス HINSTANCE hInst; char szStr[256];

commctrl.hをインクルードするのを忘れないでください。 また、Comctl32.libをリンクするのも忘れないでください。 szStrがWM_PAINメッセージが来るたびにクライアント領域に 表示されます。

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, "猫でもわかるIPアドレスコントロール", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ 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; INITCOMMONCONTROLSEX ic; HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_INTERNET_CLASSES; InitCommonControlsEx(&ic); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 10, 10, szStr, lstrlen(szStr)); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_IP: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } 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; }

WM_CREATEメッセージが来たらコモンコントロールを初期化します。

WM_PAINTメッセージが来たらszStrをクライアント領域に表示します。

メニューの「オプション」「IPアドレスを入力」(IDM_IP)が来たら ダイアログボックスを表示します。

LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hIp; static BYTE byVal[4]; LPNMIPADDRESS lpnmipa; LPARAM IpAddress; switch (msg) { case WM_INITDIALOG: hIp = GetDlgItem(hDlg, IDC_IPADDRESS1); IpAddress = MAKEIPADDRESS(byVal[0], byVal[1], byVal[2], byVal[3]); SendMessage(hIp, IPM_SETADDRESS, 0, IpAddress); SetFocus(hIp); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: case IDCANCEL: EndDialog(hDlg, IDOK); return TRUE; } return FALSE; case WM_NOTIFY: if (((LPNMHDR)lp)->hwndFrom == hIp) { lpnmipa = (LPNMIPADDRESS)lp; switch (lpnmipa->hdr.code) { case IPN_FIELDCHANGED: byVal[lpnmipa->iField] = lpnmipa->iValue; wsprintf(szStr, "1st = %d, 2nd = %d, 3rd = %d, 4th = %d", byVal[0], byVal[1], byVal[2], byVal[3]); InvalidateRect(GetParent(hDlg), NULL, TRUE); return TRUE; default: return FALSE; } } return FALSE; } return FALSE; }

ダイアログボックスのプロシージャです。

WM_INITDIALOGメッセージが来たら、MAKEIPADDRESSマクロで各フィールドの値から IPアドレスを作ります。

LPARAM MAKEIPADDRESS( BYTE b0, BYTE b1, BYTE b2, BYTE b3 );

b0, b1, b2, b3は各フィールドの値です。戻り値がDWORDではなくLPARAMなのは これをすぐにIPM_SETADDRESSメッセージとともに送信できるようにするためです。

IPM_SETADDRESS wParam = 0; lParam = (LPARAM)(DWORD)dwAddr;

このメッセージはIPアドレスの値をIPアドレスコントロールの各フィールドに 表示します。

「OK」「キャンセル」ボタンが押されたらダイアログボックスを閉じます。

IPアドレスコントロールからIPN_FIELDCHANGED通知メッセージが来たら フィールドの値をstatic変数に記憶させます。この通知メッセージはユーザーがフィールド を変えたときに送られてきます。

IPN_FIELDCHANGED lpnmipa = (LPNMIPADDRESS) lParam;

この通知メッセージはWM_NOTIFYの形で送られてきます。
lpnmipaはNMIPADDRESS構造体のアドレスです。

typedef struct tagNMIPADDRESS{ NMHDR hdr; int iField; int iValue; } NMIPADDRESS, *LPNMIPADDRESS;

hdrは毎度おなじみのNMHDR構造体です。

iFieldは変化したフィールドの番号です。

iValueはフィールドの新しい値です。

さて、ユーザーがフィールド0に値を入力して次の フィールドに移るとIPN_FIELDCHANGED通知メッセージがやってきます。 このときiFieldの値は0で、iValueの値はユーザーが入力した値です。 それで、
byVal[lpnmipa->iField] = lpnmipa->iValue;
でstatic変数にフィールドの値を保存することができます。
また、このあとszStrに書式指定でフィールドの値を書き込んで 無効領域を発生させているので、ユーザーが新しいフィールドに 移るとクライアント領域には、今入力した値が表示されます。

通知メッセージの説明のためにわざとこのようなプログラムにしましたが 欠点もあります。つまり、いくつかのフィールドに入力して、キャンセルボタン を押してもすでに入力したフィールドの値が有効になってしまう点です。

これを防ぐには「OK」ボタンが押されたときに初めて、各フィールドを 読み取ってクライアント領域に表示するようにします。この方がプログラムも ずっと簡単です。いろいろ試してみてください。


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

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