第97章 クリップボード その3


今回は、前章の知識を活用して、マウスでドラッグした矩形領域 のビットマップをクリップボードに転送するプログラムを作ります。 ビットマップをクリップボードに転送すること自体は 大して難しくはありません。

OpenClipboard(hWnd); EmptyClipboard(); SetClipboardData(CF_BITMAP, hBitmap); CloseClipboard();

という感でです。

どうせなら自分のクライアント領域だけでなくて、スクリーン全体の 好きな領域を選択したいものです。

それにはどうしたらよいのでしょうか。

簡単な方法は背景が透けていて、画面と同じ大きさのポップアップ ウィンドウを作って画面全部を覆ってしまいます。 透明なウィンドウを作ろうと思っていろいろやってみた人はいませんか。 CreateWindowEx関数を使ったり、背景をNULL_BRUSHで塗ったりしませんでしたか? でも、結局うまくいかなかったのではないでしょうか。 できたときは、クライアント領域が透明でその後ろのものが 透けて見えます。しかし、ウィンドウの大きさを変えたり、移動すると めちゃくちゃになりましたね。逆に考えると背景をNULL_BRUSH で塗るとその後ろに見えるものが背景になる、と考えてはどうでしょうか。 また、今回は大きなポップアップウィンドウは移動も、大きさの変化もしません。 この性質を利用してみましょう。

では、早速プログラムを見てみます。

// clip03.rcの一部 // 自分で作る人はWindows.hと自作ヘッダーファイルのインクルードをします ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END MENUITEM "最新表示(&R)", IDM_REDRAW MENUITEM "キャプチャー(&C)", IDM_CAP END

単なるメニューリソースです

// clip03.cpp #define STRICT #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK WholeProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); int CreateMyChild(HWND); void DrawRect(HWND, POINTS, POINTS); HWND hWhole, hMain; BOOL bCap, bBlock; POINTS beg, end, oldend; short x, y; char szClassName[] = "clip03"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

いつもと同じです。WholeProcは画面全体を覆うポップアップウィンドウの プロシージャです。

//ウィンドウ・クラスの登録 BOOL 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, "猫でもわかるクリップボード",//タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL,//親ウィンドウのハンドル、親を作るときはNULL NULL,//メニューハンドル、クラスメニューを使うときはNULL hInst,//インスタンスハンドル NULL); if (!hWnd) return FALSE; hMain = hWnd; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); CreateMyChild(hWnd); return TRUE; }

だいたいいつもと同じですが、親ウィンドウのハンドルをグローバル変数に コピーしています。また、ここで巨大なポップアップウィンドウを作っています。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HDC hdc, hdc_mem; PAINTSTRUCT ps; HBITMAP hBitmap; BITMAP bm; switch (msg) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); if (IsClipboardFormatAvailable(CF_BITMAP)) { OpenClipboard(hWnd); hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP); hdc_mem = CreateCompatibleDC(hdc); SelectObject(hdc_mem, hBitmap); GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm); BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdc_mem, 0, 0, SRCCOPY); DeleteDC(hdc_mem); CloseClipboard(); } EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0L); break; case IDM_REDRAW: InvalidateRect(hWnd, NULL, TRUE); break; case IDM_CAP: bCap = TRUE; bBlock = FALSE; ShowWindow(hWnd, SW_HIDE); Sleep(300); ShowWindow(hWhole, SW_SHOWNORMAL); break; } break; case WM_CLOSE: id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか", (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWhole); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

WM_PAINTメッセージの処理は第95章と全く同じです。クリップボードに ビットマップデータがあればこれを親のクライアント領域に表示しています。

メニューからIDM_CAPが選択されたらキャプチャー開始です。といっても 実際にマウスキャプチャーをしているわけではありません。 親ウィンドウを非表示にしてポップアップウィンドウを表示させます。 しかし、このウィンドウは背景をNULL_BRUSHで塗っているので 実際には見えません。ユーザーには親ウィンドウが消えたようにしか 見えません。ここで、注意があります。親を非表示にして ポップアップウィンドウを表示状態にするときにSleep関数を いれて少し、間をおいてください。そうしないと親が半分消えかかった 画像が残ってしまいます。どの位あけたらいいかは多分環境によると 思われます。筆者の環境では300ミリ秒くらいで充分でした。

あとのメッセージの処理は対して説明は不用ですね。

int CreateMyChild(HWND hWnd) { WNDCLASSEX wc; HINSTANCE hInst; HWND hwnd; hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); wc.cbSize = sizeof(WNDCLASSEX); wc.style = NULL; wc.lpfnWndProc = WholeProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "WHOLE"; wc.hIconSm = NULL; RegisterClassEx(&wc); hwnd = CreateWindow("WHOLE", "", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInst, NULL); if (hwnd == NULL) { MessageBox(hWnd, "Window作成失敗", "Failure", MB_OK); return -1; } hWhole = hwnd; return 0; }

ウィンドウの種類についてはについては、あまり解説をしていませんでした。

オーバーラップウィンドウには、 通常親はいません。また、ウィンドウ境界、 タイトルバー、クライアント領域を持ちます。

オーナー付きオーバーラップウィンドウというのもあります。 これは、特殊形でオーナーは常にオーバーラップウィンドウです。 また、オーナーより常に手前に表示されます。ダイアログボックスは オーナー付きオーバーラップウィンドウと考えることができます。

ポップアップウィンドウも、オーバーラップウィンドウの特殊形で タイトルバーは通常ありません。(今回の場合タイトルバーがない方が 座標の計算する上で都合がよい)ポップアップウィンドウにもオーナーを付ける ことができます。

子ウィンドウは親ウィンドウのクライアント領域内に限定されます。 子ウィンドウの親はオーバーラップ、ポップアップウィンドウの いずれでもかまいません。また、子ウィンドウ自身も子ウィンドウを 持つ(孫ウィンドウ)ことができます。注意すべきことは 親ウィンドウに描画するとその位置に子供がいても無視して子供の上に 描画してしまいます。これを防ぐにはWS_CLIPCHILDRENスタイルを指定します。

さて、話が横道にそれましたがこの関数で画面と同じ大きさのポップアップウィンドウ を作っています。また、ウィンドウハンドルをグローバル変数にコピーしています。

GetSystemMetrics関数については、 すでに第67章で解説しています。

LRESULT CALLBACK WholeProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc, hdc_mem; HBITMAP hBitmap; switch (msg) { case WM_LBUTTONDOWN: if(bCap) { bBlock = TRUE; oldend = beg = MAKEPOINTS(lp); DrawRect(hWnd, beg, oldend); SetCursor(LoadCursor(NULL, IDC_CROSS)); } break; case WM_MOUSEMOVE: if(bBlock) { end = MAKEPOINTS(lp); DrawRect(hWnd, beg, oldend); DrawRect(hWnd, beg, end); oldend = end; } break; case WM_LBUTTONUP: if(bBlock) { bBlock = bCap = FALSE; SetCursor(LoadCursor(NULL, IDC_ARROW)); end = MAKEPOINTS(lp); DrawRect(hWnd, beg, oldend); x = abs(beg.x - end.x); y = abs(beg.y - end.y); hdc = GetDC(hWnd); hdc_mem = CreateCompatibleDC(hdc); hBitmap = CreateCompatibleBitmap(hdc, x, y); if(hBitmap) { SelectObject(hdc_mem, hBitmap); StretchBlt(hdc_mem, 0, 0, x, y, hdc, beg.x, beg.y, end.x-beg.x, end.y - beg.y, SRCCOPY); OpenClipboard(hWnd); EmptyClipboard(); SetClipboardData(CF_BITMAP, hBitmap); CloseClipboard(); InvalidateRect(hWnd, NULL, TRUE); } else { MessageBeep(0); } DeleteDC(hdc_mem); ReleaseDC(hWnd, hdc); } ShowWindow(hWhole, SW_HIDE); ShowWindow(hMain, SW_RESTORE); break; default: return DefWindowProc(hWnd, msg, wp, lp); } return 0L; }

ポップアップウィンドウのプロシージャです。 前章の矩形描画と殆ど同じ構造です。ただ、違う点は左ボタンが 離されたときビットマップデータをクリップボードに転送している点です。

HBITMAP CreateCompatibleBitmap( HDC hdc, int nWidth, int nHeight );

これは、指定したデバイスと互換性のあるビットマップを作ります。

BOOL StretchBlt( HDC hdcDest, // 転送先デバイスコンテキストハンドル int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, // 転送元デバイスコンテキストハンドル int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop // ラスターオペレーション );

この関数でポップアップウィンドウで選択された領域の ビットマップをメモりデバイスコンテキストに転送しています。 あとは、クリップボードにビットマップを転送して終わりです。 このへんの手順については次章以降でもう少し詳しく解説します。

void DrawRect(HWND hWnd, POINTS beg, POINTS end) { HDC hdc; HPEN hPen; hdc = GetDC(hWhole); SetROP2(hdc, R2_NOT); hPen = CreatePen(PS_SOLID, 7, RGB(0, 0, 0)); SelectObject(hdc, hPen); MoveToEx(hdc, beg.x, beg.y, NULL); LineTo(hdc, end.x, beg.y); LineTo(hdc, end.x, end.y); LineTo(hdc, beg.x, end.y); LineTo(hdc, beg.x, beg.y); ReleaseDC(hWhole, hdc); DeleteObject(hPen); return; }

前章で作ったDrawRect関数と殆ど同じですが ペンを太くしています。


筆者のデスクトップおよびランチャープログラムの一部を コピーしたところです。


ドラッグの仕方によっては上下が反対になったり、 鏡に映したようにコピーされます。 おもしろいのでいろいろやってみてください。


[SDK Index] [総合Index] [Previous Chapter] [Next Chapter]

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