- ベストアンサー
キャレットの現在位置の表示
- Win32APIの習作としてエディタを作っているのですが,ステータスバーに現在のキャレット位置を表示する部分で困っています.
- エディットコントロールに更新が無いときにキャレット位置の更新ができないです.
- 良い方法がありましたらご教授下さい.
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
★アドバイス ・エディット・ボックスをサブクラス化してWM_KEYDOWNで カーソルキーの移動を監視。移動されていればキャレット位置の 表示をすれば良いでしょう。 http://wisdom.sakura.ne.jp/system/winapi/win32/win64.html→『サブクラス化』 http://wisdom.sakura.ne.jp/system/winapi/win32/win30.html→『キーボードイベント』
その他の回答 (1)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★アドバイス >ハンドルを得る方法は他の場面でも重要になると思いますので. ↑ ハンドルを取得する方法よりもサブクラス化したEditProcから 親プロシージャにキャレット位置の変更を通知すれば楽です。 ・仕組みは (1)EditProcでSendMessageを使いWM_APP+1などを送る (2)親プロシージャでWM_APP+1を受け取る (3)受け取ったときにステータスバーに位置を表示 サンプル: #define WM_MY_STATUSBAR (WM_APP + 1) LRESULT __stdcall WndProc(...) { static HWND hStatusbar; ←ここに書く(ここでも良いかな?) switch ( uMsg){ case WM_CREATE: ...略... // ステータスバーを作成 hStatusbar = CreateStatusWindow( …略… ); break; case WM_MY_STATUSBAR: { char str[64]; POINT pt; RECT rc; GetCaretPos( &pt ); wsprintf(str, "現在のキャレット位置 (%d, %d)",pt.y / FONT_HEIGHT, pt.x / FONT_WIDTH); SendMessage( hStatusbar, SB_SETTEXT, 1, (LPARAM)str ); GetClientRect( hStatusbar, &rc ); InvalidateRect( hStatusbar, &rc, TRUE ); break; } } return 0L; } LRESULT __stdcall EditProc(HWND hEdit, UINT uMsg, WPARAM wp, LPARAM lp) { switch ( uMsg ){ case WM_KEYDOWN: case WM_LBUTTONDOWN: SendMessage( GetParent(hEdit), WM_MY_STATUSBAR, 0, 0 ); break; } return CallWindowProc( DefEditProc, hEdit, uMsg, wp, lp ); } こんな感じでどうでしょうか。 ※インデントは全角空白を使っています。
お礼
ありがとうございます. 教えて頂いたおかげでウィンドウズの基本的な動きが 理解できてきました.
補足
WM_MY_STATUSBAR を受け取った後のキャレット位置の表示処理ですが, フォント幅は文字に依存するため,定数 FONT_WIDTH で キャレットの クライアント座標 pt.x を割って求めるとずれてしまう問題が起きました. そこで,EM_CHARFROMPOS を使用して以下のように変更してみたのですが, y 方向のスクロールバーが動き出すあたりから pt.x の値が意図しない ものになってしまいます.2Byte ずつ増えているので,どこかで \r\n を拾っているのかもしれないです. できればアドバイスを頂けないでしょうか? case WM_MY_STATUSBAR:{ char str[64]; POINT pt = {0, 0}; RECT rc; DWORD chPos; GetCaretPos(&pt); chPos = SendMessage(hEdit, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)); pt.y = HIWORD(chPos); chPos = SendMessage(hEdit, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, 0)); pt.x = LOWORD(chPos); wsprintf(str, "現在のキャレット位置 (%d, %d)", pt.y, pt.x); SendMessage(hStatusbar, SB_SETTEXT, 1, (LPARAM)str); GetClientRect(hStatusbar,&rc); InvalidateRect(hStatusbar, &rc, TRUE); break;} ※インデントに全角スペースを使いました.
お礼
アドバイスありがとうございます. リンクを参考に下記のように変更し, ひとまず目的を達成できました. しかし, hStatusbar が, EditProc() 内で取得する方法がわからなかったため, グローバルになってしまいました. FindWindow() という関数で hStatusbar を取得しようと 思ったのですが,CreateStatusWindow() を使用しているので クラス名とウィンドウ名がわかりません. できればこれも解決法をお願いします. ハンドルを得る方法は他の場面でも重要になると思いますので. // MyEditor.c static HWND hStatusbar; int __stdcall WinMain(...){} LRESULT __stdcall EditProc(HWND hEdit, UINT uMsg, WPARAM wp, LPARAM lp) { switch (uMsg) { case WM_KEYDOWN: case WM_LBUTTONDOWN:{ char str[64] = {0}; POINT pt = {0, 0}; RECT rc = {0, 0, 0, 0}; GetCaretPos(&pt); wsprintf(str, "現在のキャレット位置 (%d, %d)",pt.y / FONT_HEIGHT, pt.x / FONT_WIDTH); SendMessage(hStatusbar, SB_SETTEXT, 1, (LPARAM)str); GetClientRect(hStatusbar, &rc); InvalidateRect(hStatusbar, &rc, TRUE); break;} } return CallWindowProc(DefEditProc, hEdit, uMsg, wp, lp); } LRESULT __stdcall WndProc(...) { ...略... switch (uMsg) { case WM_CREATE: GetClientRect(hWnd, &rc); hEdit = CreateMultilineEditWindow(hWnd, rc); // エディットウィンドウのサブクラス化 DefEditProc = (WNDPROC)GetWindowLong(hEdit, GWL_WNDPROC); SetWindowLong(hEdit, GWL_WNDPROC ,(LONG)EditProc); // コモンコントロール関係の初期化 InitCommonControls(); // ステータスバーを作成 hStatusbar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, "ステータスバー", hWnd, IDC_STATUS); SendMessage(hStatusbar, SB_SETPARTS, MY_SB_PART_COUNT, (LPARAM)rightEdgePosition); break; ...略... } return 0L; }