プロが教える店舗&オフィスのセキュリティ対策術

 Win32APIの習作としてエディタを作っているのですが,
ステータスバーに現在のキャレット位置を表示する部分で困っています.
いろいろ調べて下記のコードを書いてみたのですが,
エディットコントロールに更新が無いとき(矢印キーで移動など)
にキャレット位置の更新ができないです.
良い方法がありましたらご教授下さい.
(ここのサンプルコードが良いとかでもありましたらお願いします.)

////////////////////////////////////////////////////////////////
// MyEditor.c

static const int FONT_WIDTH = 6;
static const int FONT_HEIGHT = 18;

int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
...略...
}

LRESULT __stdcall WndProc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
...略...
switch (uMsg) {
...略...
case IDC_EDIT:{
char str[64];
POINT pt = {0, 0};
RECT rc = {0, 0, 0, 0};
GetCaretPos(&pt);
wsprintf(str, "現在のキャレット位置 (%d, %d)",
pt.x / FONT_WIDTH, pt.y / FONT_HEIGHT);
SendMessage(hStatusbar, SB_SETTEXT, 1, (LPARAM)str);
GetClientRect(hStatusbar,&rc);
InvalidateRect(hStatusbar, &rc, TRUE);
break ;}
...略...
}
return 0L;
}

A 回答 (2件)

★アドバイス


・エディット・ボックスをサブクラス化してWM_KEYDOWNで
 カーソルキーの移動を監視。移動されていればキャレット位置の
 表示をすれば良いでしょう。
 http://wisdom.sakura.ne.jp/system/winapi/win32/w …→『サブクラス化』
 http://wisdom.sakura.ne.jp/system/winapi/win32/w …→『キーボードイベント』
    • good
    • 0
この回答へのお礼

 アドバイスありがとうございます.
リンクを参考に下記のように変更し,
ひとまず目的を達成できました.
しかし, 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;
}

お礼日時:2008/05/28 21:59

★アドバイス


>ハンドルを得る方法は他の場面でも重要になると思いますので.
 ↑
 ハンドルを取得する方法よりもサブクラス化した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;}
※インデントに全角スペースを使いました.

補足日時:2008/05/29 22:05
    • good
    • 0
この回答へのお礼

ありがとうございます.
教えて頂いたおかげでウィンドウズの基本的な動きが
理解できてきました.

お礼日時:2008/05/29 21:48

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!