1

以下に私の問題を英語で説明しましたが、これは視覚的な問題なので、すべてを読みたくない場合は、一番下の図を見てください)。

私は自分のクラスの逆ポーランド記法電卓の構築に取り組んでおり、GUI のボタン コントロールが正常に動作する編集コントロールに値を追加できるようにすることを完了しましたが、キャレットが何か変なことをしていて、できます。それに関する情報は見つかりません。

エディット コントロールにカスタム メッセージを送信して、コントロール内の現在のテキストの長さを確認し、テキストの最後にキャレットを配置して、追加する必要があるテキストを追加できるようにします (右揃えでES_RIGHT)、これも問題なく機能しますが、キャレットが可能な限り正しい場所にある場合、ほとんどの数字の真ん中に配置されます。

これは、キャレットが配置できる最も適切な場所でのみ発生するようです (つまり、キャレットが前の文字の右側に直接配置されている場所)。キーボード/マウスを使用して配置し、定義した幅のオフセットが最後の場所をわずかにずらしただけであることを期待して、ウィンドウの寸法を調整しようとしましたが、問題は解決せず、難しくなりますテキスト フィールドの最後の文字を読み取ります。

関連コード:

LRESULT CALLBACK EditBoxClass::WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_COMMAND:
        break;
    case WM_APPEND_EDIT:
        /* Get current length of text in the box */
        index = new int( GetWindowTextLength (hWnd) );
        SetFocus( hWnd );
        /* Set the caret to the end of the text in the box */
        SendMessage( hWnd, EM_SETSEL, (WPARAM)index, (LPARAM)index );
        /* "Replace" the selection (the selection is actually targeting 
            nothing and just sits at the end of the text in the box) 
            with the passed in TCHAR* from the button control that 
            sent the WM_APPEND_EDIT message */
        SendMessage( hWnd, EM_REPLACESEL, 0, lParam );
        break;
    }
    return CallWindowProc( EditClassStruct.GetOldProc(), hWnd, msg, wParam, lParam );
}

問題の写真:

画像

4

2 に答える 2

1

これが原因かもしれませんし、そうでないかもしれませんが、あなたは を誤用していますEM_SETSEL。ヒープ上に を動的に割り当て (そしてリークし) int、メッセージ パラメーターとしてそのポインターを渡していますが、EM_SETSEL最初からポインターを想定または使用していません。したがって、動的割り当てを取り除きます。

また、デフォルトのウィンドウ プロシージャはメッセージの処理方法を認識しないWM_APPEND_EDITため、メッセージを に渡しても意味がありませんCallWindowProc()

代わりにこれを試してください:

case WM_APPEND_EDIT:
{
    /* Get current length of text in the box */
    int index = GetWindowTextLength( hWnd );
    SetFocus( hWnd );
    /* Set the caret to the end of the text in the box */
    SendMessage( hWnd, EM_SETSEL, (WPARAM)index, (LPARAM)index );
    /* "Replace" the selection (the selection is actually targeting 
        nothing and just sits at the end of the text in the box) 
        with the passed in TCHAR* from the button control that 
        sent the WM_APPEND_EDIT message */
    SendMessage( hWnd, EM_REPLACESEL, 0, lParam );
    return 0;
}

そうは言っても、EM_GETRECT/を使用して、エディット コントロールの書式設定用の四角形EM_SETRECTの右端を数ピクセル拡張してみてください。これにより、キャレットに追加の作業スペースが与えられるはずです。

于 2014-05-31T21:02:56.877 に答える
1

同じ問題に直面し、この回答で最初のアプローチを提示した後、2 つの適切に機能するソリューションを提供します。この不具合を適切に修正する方法は他にないと思います (WinAPI のこの部分を担当する Microsoft プログラマでない限り)。

で作成された編集コントロールでこの問題を修正する方法を考えていましたES_MULTILINEが、この問題は単一行の編集コントロールでのみ発生するようです (Windows 7 64 ビットでテスト済み)。Visual Styles を有効にすることも役に立ちますが、問題はまだ残っています (少なくともオフセットはそれほど明白ではありません)。

説明

通常、キャレットが一番右の位置にある場合、x 値 ( によって提供される) は、によって提供される値GetCaretPos ()と等しくなければなりません(エディット コントロールが で作成された場合)。不明な理由により、これは当てはまりません。したがって、キャレットの位置が少なくとも値の近くにあるかどうかを確認する必要があります (ただし、最後の文字の幅よりも遠くない)。したがって、このタスクを実行するには 2 つの可能性があります。rect.rightEM_GETRECTES_RIGHTrect.right

  1. を使用して外側の右文字の幅を計算し、withを呼び出すことによって提供される値GetTextExtentPoint32 ()からそれを減算し、キャレットの x 位置が結果よりも大きいかどうかを確認する必要があります ORrect.rightSendMessage ()EM_GETRECT
  2. rect.right値と外側の右キャレット位置 (私の場合)の間のマージンを計算し、3この値をハードコーディングされたオフセットとして使用して簡単なチェックを行う必要があります。

これらの手順の後 (選択した手順に関係なく)、必要に応じてキャレットの位置を変更する必要があります。

1.アプローチ(推奨)

    case WM_LBUTTONDOWN: {
        TRACKMOUSEEVENT tme = {sizeof (tme), TME_LEAVE, hwnd, HOVER_DEFAULT};
        TrackMouseEvent (&tme);
    }
    break;

    case WM_KEYDOWN:
    case WM_MOUSELEAVE:
    case WM_SETCURSOR: {
        DefSubclassProc (hwnd, message, wParam, lParam);

        DWORD end;
        SendMessage (hwnd, EM_GETSEL, (WPARAM) NULL, (LPARAM) &end);
        int len = GetWindowTextLength (hwnd);
        if (end < len || len <= 0)
            return TRUE;

        wchar_t *buffer = new wchar_t[len + 1];
        GetWindowText (hwnd, buffer, len + 1);
        wchar_t lastChar[] = {buffer[len - 1], '\0'};
        delete[] buffer;

        SIZE size;
        HDC hdc = GetDC (hwnd);
        if (hdc == NULL)
            return TRUE;

        GetTextExtentPoint32 (hdc, lastChar, 1, &size);
        ReleaseDC (hwnd, hdc);

        POINT pt;
        RECT rect;

        GetCaretPos (&pt);
        SendMessage (hwnd, EM_GETRECT, (WPARAM) 0, (LPARAM) &rect);
        if ((rect.right - size.cx) <= pt.x)
            SetCaretPos (rect.right, pt.y);

        return TRUE;
    }
    break;

2.アプローチ(改良版オリジナル)

    case WM_LBUTTONDOWN: {
        TRACKMOUSEEVENT tme = {sizeof (tme), TME_LEAVE, hwnd, HOVER_DEFAULT};
        TrackMouseEvent (&tme);
    }
    break;

    case WM_KEYDOWN:
    case WM_MOUSELEAVE:
    case WM_SETCURSOR: {
        DefSubclassProc (hwnd, message, wParam, lParam);

        POINT pt;
        RECT rect;

        GetCaretPos (&pt);
        SendMessage (hwnd, EM_GETRECT, (WPARAM) 0, (LPARAM) &rect);
        if ((rect.right - pt.x) <= 3)
            SetCaretPos (rect.right, pt.y);

        return TRUE;
    }
    break;

編集コントロールをサブクラス化する必要があります。次に、このコードをウィンドウ プロシージャで使用して楽しんでください。どちらの場合も、マウス イベントの追跡は絶対に必要というわけではありませんが、この不具合を完全に回避するために推奨されます。を呼び出すDefSubclassProc ()と、マウスオーバー時にカーソルが確実に変更されます。

于 2015-11-16T22:33:00.230 に答える