横幅がぐりぐり変わり、複数行表示可能なエディットコントロールを、文字列にあわせて、高さを調節したい。
DrawText 関数に、 DT_CALCRECT フラグを設定することで、指定した幅に収まる文字列を表示するのに必要な矩形の取得だけをすることができる(描画されない)。
コレを使ってコントロールの高さを計算し直せば実現できる。
上のエディットコントロールを書き換えると、その文字列が下のエディットコントロールに反映され、サイズが変更されるようなサンプルを作った。
ばりばり ATL/WTL 使ったコードだが、基本的に普通にWin32API呼んでも同じようにできる。
二つのエディットコントロール( IDC_EDIT1 と IDC_EDIT2 )を、あらかじめCEditにアタッチしておく( CEdit ce1 と CEdit ce2 )。
とりあえず、サイズが変更されたときと、IDC_EDIT1の文字を変更した時に、サイズ変更関数を呼ぶようにしておく。
LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
// IDC_EDIT2のサイズ変更
ChangeEdit2Height();
// DlgResize実行するため、ハンドルしなかったことにする
bHandled = FALSE;
return 0;
}
LRESULT OnEdit1Change(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
// atlmisc.h インクルードしとく
CString strBuff;
// 文字をコピペ
int nstrLen = ce1.GetWindowTextLength() + 2;
ce1.GetWindowText(strBuff.GetBuffer(nstrLen), nstrLen);
strBuff.ReleaseBuffer();
strBuff.Replace(_T("<br>"), _T("\x0D\x0A"));
ce2.SetWindowText(strBuff);
// IDC_EDIT2のサイズ変更
ChangeEdit2Height();
return 0;
}
そのサイズ変更関数では、ce2のデバイスコンテキストとフォントを使って、テキストボックスの横幅領域に収まる文字列の高さを取得する。
テキストボックスの文字列領域を取得するとき、.GetRect(RECT&)を使わずに.ClientRect(RECT&)を使ってしまうと、サイズが合わ無くなってしまうので注意。
後は DrawText 関数でそこに収まる文字の領域を計算すればよい。
計算した領域は LPRECT 型の引数が示す先に書き込まれるが、その高さが関数の戻り値にでも取得するので、それを利用する。
(つまり、LPRECT 型の引数に示したRECT変数は書き換わってしまうので、後で利用する際は注意)
void ChangeEdit2Height(){
// 文字列の取得
CString strBuff;
int nstrLen = ce2.GetWindowTextLength() + 2;
ce2.GetWindowText(strBuff.GetBuffer(nstrLen), nstrLen);
strBuff.ReleaseBuffer();
// IDC_Edit2のサイズ変更
CDCHandle cdcE2(ce2.GetDC()); // デストラクタでリリースされない
cdcE2.SelectFont(ce2.GetFont()); // フォントをコントロールに会わせる
CRect rc2W, rc2R; // ウィンドウRectと、フォーマット領域Rect
ce2.GetWindowRect(&rc2W); this->ScreenToClient(&rc2W);
ce2.GetRect(&rc2R);
rc2W.bottom += -rc2R.Height() + cdcE2.DrawText(strBuff, -1, &rc2R, DT_EDITCONTROL | DT_WORDBREAK | DT_NOPREFIX | DT_CALCRECT);
if(rc2R.Height() != 0) ce2.MoveWindow(&rc2W); // 0pxで更新すると、rc2Rの高さがあるのでおかしくなる
ce2.ReleaseDC(cdcE2);
return;
}
わかりやすいようにダイアログボックスの背景を黒に塗りつぶしてみた。
横幅を変えるだけで、きれいにエディットコントロールの高さが変わってるのがわかる。
英文なら、単語単位でしっかり折り返される。