63868
MFCで、タブコントロール上に表示する子ダイアログを作成して、ダイアログエディタ上でボタンコントロールを追加してデバッグ実行すると、ボタンコントロールを貼り付けた位置よりもやや左下にボタンコントロールがずれて描画されているように見えるというバグで困っています。

※1.
単純にダイアログエディタ上でボタンコントロールをずれたぶんだけ右上にドラッグ&ドロップすれば解決するのですが、ダイアログエディタ上とデバッグ実行中でコントロールの描画位置に差異のないようにしたいです。

※2.
MoveWindow関数等のコントロールを移動する関数を使えば、解決するかもしれませんが、コントロールを追加する毎にその処理を読んだりメンバ変数を作らなければならないので、修正がなるべく少ない方法を教えて頂きたいです。

【ダイアログエディタ上でボタンコントロールを追加した位置とデバッグ実行中のボタンコントロールの位置の差異】  
[![画像の説明をここに入力](https://i.stack.imgur.com/JJgga.png)](https://i.stack.imgur.com/JJgga.png)

解決策のご回答をお願い致します。
CC BY-SA 4.0
2020-03-14T10:45:48.340
63828
2020-03-16T02:06:26.910
2020-03-14T12:07:54.700
21034
21034
question
mfc
MFCで、タブコントロール上に表示する子ダイアログ上のコントロール位置をダイアログエディタ上とデバッグ実行中で一致させたい
CTabCtrlにCDialogを埋め込む(VC++)  
<https://www.kazetest.com/vcmemo/dlgintab/dlgintab.htm>  
を参考してください。  
CWnd類のクラスをCTabCtrlの子Windowとして生成し、子WindowのCWnd::OnPaintなどのハンドルを実装すればと思います。
CC BY-SA 4.0
2020-03-15T03:54:19.593
63854
2020-03-15T03:54:19.593
38209
63828
answer
**まず、質問の現象はバグではなく正常な動作でしょう。**

子ダイアログをタブコントロールに組み込んだ時点で、子ダイアログの原点(0, 0)はタブコントロールの「To Do」の文言の下になっているでしょう。  
質問記事の図で言えば、以下のように **子ダイアログとタブコントロールの緑色の十字の位置が同じ原点(0, 0)** と思われます。
**質問の意図としては赤色の十字の位置を子ダイアログの原点(0, 0)にしたい** のでしょうが、簡単には出来ないでしょうね。(ピンクの部分は後述)

[![回答画像](https://i.stack.imgur.com/Kwt7d.jpg)](https://i.stack.imgur.com/Kwt7d.jpg)

子ダイアログの表示位置・サイズを調節することは可能ですが、以下のような課題があります。  
それらの課題があったとしても表示位置・サイズを調節したいかどうか、を考えてみてください。

例えば @Cold Starch Jelly さんの紹介記事では以下の箇所でタブコントロール上の子ダイアログ表示位置・サイズを設定しています。

>
```

>     // サイズを計算する
>     CRect r;
>     m_ctrlTab.GetClientRect(&r);
>     r.left +=2;
>     r.right -=4;
>     r.top += 20;
>     r.bottom -= 4;
>  
>     // ダイアログを、タブの子ウィンドウとして作る
>     m_pDlg1 = new CDlg1(&m_ctrlTab);  
>     m_pDlg1->Create(CDlg1::IDD, &m_ctrlTab);
>     m_pDlg1->MoveWindow(&r);
>  
```

表示結果は以下になります。

[![初期画像](https://i.stack.imgur.com/Kisi0.png)](https://i.stack.imgur.com/Kisi0.png)

これを特に工夫せず上記の表示位置・サイズ計算をコメントアウトして、`m_ctrlTab.GetClientRect(&r)`で取得した情報をそのまま`m_pDlg1->MoveWindow(&r)`にすると以下のようになり、タブコントロールのタブキャプション部分等が覆い隠されてしまいます。

[![位置だけ調整画像](https://i.stack.imgur.com/dSNef.png)](https://i.stack.imgur.com/dSNef.png)

そのため、いったん表示範囲を限定するためのウィンドウを間に挟んで、今は子ウィンドウとなっているものを孫ウィンドウとする形にします。  
ただし、 **子ウィンドウでクリッピングするため、孫ウィンドウの上端と左端(上記質問記事図のピンク色の部分)は常に表示されなくなります。**

>
```

>     // サイズを計算する
>     CRect r;
>     m_ctrlTab.GetClientRect(&r);
>     r.left +=2;
>     r.right -=4;
>     r.top += 20;
>     r.bottom -= 4;
>  
>     // 孫ウィンドウをクリッピングする子ウィンドウを作成する
>     pW1 = new CWnd();  // CWnd* pW1;を .hに追加しておく
>     pW1->Create(_T("STATIC"), NULL, WS_CHILD | WS_VISIBLE, r, &m_ctrlTab,
> 145);
>     pW1->MoveWindow(&r);
>  
>     // ダイアログを、タブの孫ウィンドウとして作る
>     m_pDlg1 = new CDlg1(pW1);
>     m_pDlg1->Create(CDlg1::IDD, pW1);
>     CRect c1;
>     c1.left = -15; // 孫ウィンドウの表示位置調節
>     c1.top  = -15; // 以下同じ
>     c1.right = r.right - r.left;
>     c1.bottom = r.bottom - r.top;
>     m_pDlg1->MoveWindow(&c1);
>  
>     // 子＆孫ウィンドウの表示
>     pW1->ShowWindow(SW_SHOW);
>     m_pDlg1->ShowWindow(SW_SHOW);
>  
>     // OnTcnSelchangeTab1()の表示切替処理
>     if (m_ctrlTab.GetCurSel() == 0)
>     {
>         pW1->ShowWindow(SW_SHOW);
>         m_pDlg1->ShowWindow(SW_SHOW);
>         pW2->ShowWindow(SW_HIDE);
>         m_pDlg2->ShowWindow(SW_HIDE);
>     }
>     else
>     {
>         pW2->ShowWindow(SW_SHOW);
>         m_pDlg2->ShowWindow(SW_SHOW);
>         pW1->ShowWindow(SW_HIDE);
>         m_pDlg1->ShowWindow(SW_HIDE);
>     }
>  
```

こちらの表示結果は以下になります。

[![クリッピング画像](https://i.stack.imgur.com/6lx5o.png)](https://i.stack.imgur.com/6lx5o.png)
CC BY-SA 4.0
2020-03-15T12:43:56.417
63868
2020-03-15T12:49:45.227
2020-03-15T12:49:45.227
26370
26370
63828
answer
ダイアログリソースなど、リソース上でのコントロールの位置とサイズは「ピクセル」ではなく「ダイアログ単位(=Dlu)」という特殊な単位で指示、算定されます。  
それを表示する場合にはピクセル値に換算されるのですが、その際フォントのサイズなどの考慮されるなど、単純な換算方法ではありません。  
(基準はありますが、フォントを変更した場合等は考慮されていません)

従って、厳密な配置は、ダイアログエディター上や、リソースファイルの直接編集によってすら不可能です。  
これはWindowsの伝統的な仕様ですので、覆す手段を考えるのは時間の無駄です。

一般に子コントロールの厳密な配置が必要になった場合には、その親がWM_SIZEを受領した時点で全て再計算(ピクセルで)するのが一般的な解決手段となります。
CC BY-SA 4.0
2020-03-16T02:06:26.910
63879
2020-03-16T02:06:26.910
3793
63828
answer