WindowsCE5.0/EMbeddedVC++4.0SP4/SDK(MFC未使用)にて開発
お世話になります。
7桁入力のエディットコントロールで、
①7桁入力すると先頭にキャレットが移動
②キャレットの位置に常に上書き
というような仕様を要求されています。
①についてはWM_COMMAND メッセージでEN_CHANGEを
つかまえて制御できるのですが、
②についてはどうすべきかわかりません。
上書きモードにする設定があればよいのですが見つかりません。
自作するにはどのようにすればよいのでしょうか?
具体的な方法がありましたらご教示ください。
こんな感じかなぁ
・7桁入力まではなにもしない
・7桁になったら1文字選択にする
サブクラス化でキー入力とマウス入力をうけてEM_SETSELしてみました
#define NUM_INPUT 7
LONG m_pOrgWndProc ;
HWND m_hEdit ;
void OnNumKeiChange(void) ;
void OnNumSelChange(void) ;
static LRESULT CALLBACK EditSubWindowProc(HWND hwnd,UINT msg,WPARAM
wparam,LPARAM lparam)
{
/* メッセージを奪う */
switch(msg) {
case WM_KEYDOWN:
case WM_KEYUP:
OnNumKeiChange() ;
break ;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
OnNumSelChange() ;
break ;
default :
break ;
}
return ::CallWindowProc((WNDPROC)m_pOrgWndProc, hwnd, msg, wparam, lparam);
}
HWND CreateNumEdit(HWND hParent, RECT rectWnd, HINSTANCE hInstance)
{
m_hEdit = CreateWindow(_T(edit), NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT ,
rectWnd.left, rectWnd.top, rectWnd.right, rectWnd.bottom,
hParent, (HMENU)ID_EDIT, hInstance, NULL) ;
m_pOrgWndProc = GetWindowLong(m_hEdit,GWL_WNDPROC);
SetWindowLong(m_hEdit,GWL_WNDPROC,(LONG)EditSubWindowProc);
return m_hEdit ;
}
/* エディットコントロールからのWM_COMMANDの処理 */
void OnNumEditCommand(WPARAM wParam, LPARAM lParam)
{
int iStart ;
int iEnd ;
int iLength ;
if(HIWORD(wParam) == EN_UPDATE) {
iLength = ::SendMessage(m_hEdit, EM_LINELENGTH, -1, 0) ;
if(iLength == NUM_INPUT) {
::SendMessage(m_hEdit, EM_GETSEL,(WPARAM)&iStart, (LPARAM)&iEnd) ;
if(iStart >= NUM_INPUT) {
iStart = 0 ;
}
iEnd = iStart + 1 ;
::SendMessage(m_hEdit, EM_SETSEL ,iStart, iEnd) ;
}
}
}
void OnNumKeiChange(void)
{
int iStart ;
int iEnd ;
int iLength ;
iLength = ::SendMessage(m_hEdit, EM_LINELENGTH, -1, 0) ;
::SendMessage(m_hEdit, EM_GETSEL,(WPARAM)&iStart, (LPARAM)&iEnd) ;
TRACE(G %d %d\n, iStart, iEnd) ;
if(iLength == NUM_INPUT) {
if(iStart == iEnd) {
if(iStart > NUM_INPUT) {
iStart = 0 ;
}
if(iStart > 0) {
iStart -= 1 ;
}
iEnd = iStart + 1 ;
::SendMessage(m_hEdit, EM_SETSEL ,iStart, iEnd) ;
}
else if((iStart + 1) != iEnd) {
iEnd = iStart + 1 ;
::SendMessage(m_hEdit, EM_SETSEL ,iStart, iEnd) ;
}
}
}
void OnNumSelChange(void)
{
int iStart ;
int iEnd ;
int iLength ;
iLength = ::SendMessage(m_hEdit, EM_LINELENGTH, -1, 0) ;
::SendMessage(m_hEdit, EM_GETSEL,(WPARAM)&iStart, (LPARAM)&iEnd) ;
if(iLength == NUM_INPUT)
{
if(iStart == iEnd) {
if(iStart == NUM_INPUT) {
iStart -= 1 ;
}
iEnd = iStart + 1 ;
::SendMessage(m_hEdit, EM_SETSEL ,iStart, iEnd) ;
}
else if((iStart + 1) != iEnd) {
iEnd = iStart + 1 ;
::SendMessage(m_hEdit, EM_SETSEL ,iStart, iEnd) ;
}
}
}
solid 様 ありがとうございました。
実は、キャレット形状を■としていましたので、実現に手間取りました。
結果として、次のようにしてみました。
・エディットをスーパークラス化する(詳細については、ここでは省略)
・入力文字数が制限桁数未満は■形状、制限桁数以上はI型にキャレット形状を変える。
・キャレット選択と形状の制御は次のようにしました。
(便宜上メッセージ処理の後半から記載します)
・・・・・・・・・・・・・・・・・・
case WM_KEYUP:
OnNumSelChange(hwnd) ; // 後方参照して!!
break ;
case WM_LBUTTONUP:
OnNumSelChange(hwnd) ; // 後方参照して!!
break ;
case WM_KILLFOCUS: //エディットのフォーカスが失われた
DestroyCaret(); //キャレット削除
break;
case WM_SETFOCUS: //エディットにフォーカス
lr = CallWindowProc( lpfnDefButtonProc, hwnd, msg, wParam, lParam );
//デフォルトのプロシージャを実行
OnNumSelChange(hwnd) ; // 後方参照して!!
return lr; // 本来の動きでリターン
break;
}
// デフォルトのプロシージャを保存を呼び出す
return CallWindowProc(lpfnDefButtonProc, hwnd, msg, wParam, lParam);
}
void OnNumSelChange(HWND hwnd)
{
int iStart,iEnd;
int iLength , iLimit;
SIZE size;
iLength = SendMessage(hwnd, EM_LINELENGTH, -1, 0) ;
// 現在の入力済み文字列を取得
SendMessage(hwnd, EM_GETSEL,(WPARAM)&iStart, (LPARAM)&iEnd);
// 現在のキャレットの位置を取得
iLimit = SendMessage(hwnd, EM_GETLIMITTEXT, 0, 0);
// MAXの入力文字を取得
// 入力桁数に合わせてキャレットの形状を変える
s_GetFontsize(hwnd, 1, &size);
// コントロールのフォントより 1 文字数分の幅を取得
if(iLength != iLimit) {
// 制限数未満の入力がある場合
CreateCaret(hwnd, NULL, size.cx, size.cy);
//フォントサイズ相当の■のテキストカーソル(キャレット)作成
}else{
// 制限数以上の入力がある場合
CreateCaret(hwnd, NULL, 0, size.cy);
//フォントサイズ相当のIのテキストカーソル(キャレット)作成
// (幅0:システムが定義するウィンドウ境界線の幅)
if(iStart == iEnd) {
// 選択状態でない場合
if(iStart == iLimit) { // 文字列の右端
iStart -= 1 ;
}
iEnd = iStart + 1 ;
}else if((iStart + 1) != iEnd) { // 1文字選択でない場合
iEnd = iStart + 1 ;
}
}
SendMessage(hwnd, EM_SETSEL ,iStart, iEnd) ; //キャレット位置更新
// CreateCaretのあとはShowCaret 関数を呼び出してそのキャレットを
// 可視状態にするまでは、非表示の状態なので
ShowCaret(hwnd); //キャレット表示
}
動作は一応期待通りになりましたので、解決とさせていただきます。