自作の子ウィンドウを2つ以上表示するには?


__stdcall  2005-01-11 23:25:12  No: 55963

WinXP VC++6.0 SDK

はじめまして。
エディットコントロールのようなものを自作しようと思いまして、
まず、キーボードの押された文字を表示するだけのプログラムを作りました。

しかし、親ウィンドウに、その子ウィンドウを2つ以上貼り付けると、
2つに書かれている文字列が同じになってしまいます。
エディットコントロールのように2つ以上貼り付けても、違う文字列を表示するには
どうすればよいのでしょうか。

//押された文字を表示するソース

  static HWND hEdit1, hEdit2;
         WNDCLASS wc;
  case WM_CREATE:
             wc.style         = CS_HREDRAW | CS_VREDRAW;
             wc.lpfnWndProc   = EditProc;
             wc.cbClsExtra    = 0;
             wc.cbWndExtra    = 0;
             wc.hInstance     = hInstance;
             wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
             wc.hCursor       = LoadCursor(NULL, IDC_IBEAM);
             wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
             wc.lpszMenuName  = NULL;
             wc.lpszClassName = "EditTest";
             RegisterClass(&wc);
             hEdit1 = CreateWindow("EditTest", NULL,
                            WS_CHILD | WS_VISIBLE,
                            0, 0, 0, 0, hWnd, (HMENU)150, hInstance, NULL);
             hEdit2 = CreateWindow("EditTest", NULL,
                            WS_CHILD | WS_VISIBLE,
                            0, 0, 0, 0, hWnd, (HMENU)151, hInstance, NULL);
       break;
//省略
LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  static char szText[1000];
//省略
  case WM_CHAR:
      wsprintf(szText, "%s%c", szText, wParam);
      InvalidateRect(hWnd, NULL, FALSE);
       break;
  case WM_PAINT:
      hDC = BeginPaint(hWnd, &ps);
      TextOut(0, 0, szText, lstrlen(szText));
      EndPaint(hWnd, &ps);
       break;
//<省略


YuO  2005-01-11 23:58:50  No: 55964

szTextをstaticにしたのはなぜですか?
ちゃんと考えれば,szTextがstaticではまずいことはわかるはずです。

WNDCLASS::cbWndExtraで用意したエクストラ領域を使って,
それぞれのコントロールの情報をコントロールごとに保持させる必要があります。


シャノン  2005-01-12 00:01:08  No: 55965

ウィンドウごとに、テキストを覚えておく領域を別にすればよいのではないでしょうか。
現状、2つのウィンドウはウィンドウプロシージャを共有し、その中にある szText も共有しています。
これを、ウィンドウごとに個別のデータ領域にテキストを記憶させておけばよいと思われます。
cbWndExtra か SetProp などを活用してみては?


シャノン  2005-01-12 00:01:31  No: 55966

かぶった^^;;


__stdcall  2005-01-12 00:31:55  No: 55967

返答ありがとうございます。

cbWndExtraのヘルプを見てみました。
しかしながら、cbWndExtraで割り当てたエクストラ領域に個別のデータを
どのように記憶させるのでしょうか。
見当違いなことを言っているかもしれませんが、おねがいします。


シャノン  2005-01-12 00:33:52  No: 55968

SetWindowLong を使います。


__stdcall  2005-01-12 01:09:09  No: 55969

このソースの場合
wc.cbWndExtra = 0;

wc.cbWndExtra = 1000;
に変え、
EditProcのWM_CREATEの初めに
SetWindowLong(hWnd, 0, (LONG)&szText);
と書けばよいのでしょうか。


シャノン  2005-01-16 22:02:36  No: 55970

遅レス。

> と書けばよいのでしょうか。

それはたぶん違うだろうな…と思いつつ、そんなことしたことがなかったのでデマ言っちゃマズいと、自分でも試してみることに。
子ウィンドウにフォーカスが来ない。何故だ…
何か初歩的なことで詰まっている気がしてならないなぁ。

というわけで、若干自信喪失気味な予測でよろしければ。
まず、cbWndExtra はたぶん 4。
で、SetWindowLong で設定する値は、malloc なり new なりで動的に確保する。もちろん、終了時に破棄を忘れずに。

現状、なぜ static なのかといえば、EditProc から抜けた後でも値を保持させ続けたいからでしょう。
が、そのために、2つのウィンドウプロシージャで変数を共有してしまっている。
static にしちゃダメなんだけど、EditProc から抜けた後でも値を保持させ続けたいならば…子ウィンドウが存在する限り終わらない関数(つまり WinMain)で宣言するか、あるいは動的に確保するか。個人的には後者がオススメです。


Ban  2005-01-17 06:58:35  No: 55971

> wc.cbWndExtra = 1000;

どこまで取れるのか確認したことはありませんが、
この領域をあまり大きくとるのは多分よろしくありませんから、
文字バッファを直接とるのはやめた方がいいと思います。
> SetWindowLong(hWnd, 0, (LONG)&szText);
ではそう使ってませんけど(単に無駄領域)。

> というわけで、若干自信喪失気味な予測でよろしければ。
> まず、cbWndExtra はたぶん 4。

ポインタを格納するだけならポインタのサイズでいいはずです。
一応(Win64等も考えると)即値よりは sizeof をお勧めします。


Ban  2005-01-17 07:04:08  No: 55972

用法にもよりますが、GWL_USERDATA でも十分な気が。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加