Win32编辑控件插入位置偏移

时间:2014-05-31 18:14:52

标签: winapi win32gui windows-messages windows-controls

我在下面给出了我的问题的英文解释,但这是一个视觉问题所以如果你不想阅读它只是看看底部的图片。)

我正在为我的班级构建一个反向抛光符号计算器,我刚刚完成了我的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 );
}

问题图片:

image

2 个答案:

答案 0 :(得分:1)

这可能是原因,也可能不是原因,但您滥用EM_SETSEL。您正在堆上动态分配(和泄漏)int并将指针作为消息参数传递给它,但EM_SETSEL不期望或使用指针开始。所以摆脱动态分配。

此外,默认窗口proc不会知道如何处理您的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将编辑控件formatting rectangle的右边缘展开几个像素。这应该给予插入符号一些额外的工作空间。

答案 1 :(得分:1)

在面对同样的问题并在这个答案中展示我的第一个方法之后,我现在将提供两个很好的解决方案。我认为没有其他方法可以正确解决这个故障(除非你是负责WinAPI这一部分的微软程序员)。

我想知道如何在使用ES_MULTILINE创建的编辑控件上修复此问题,但这个故障似乎只是单行编辑控件上的问题(在Windows 7 64位上测试)。启用视觉样式也很有帮助,但问题仍然存在(偏移至少不那么明显)。

说明

通常,当插入符号位于最右侧位置时,它的x值(由GetCaretPos ()提供)应等于rect.right提供的EM_GETRECT值(当编辑控件为使用ES_RIGHT创建。由于原因不明,情况并非如此。因此,您必须检查插入位置是否至少在rect.right值附近(但不比最后一个字母宽)。所以你有两种可能性来完成这项任务:

  1. 您必须使用GetTextExtentPoint32 ()计算外部右侧字符的宽度,并使用rect.right调用SendMessage ()提供的EM_GETRECT值减去它,并检查x位置插入符号大于结果或不是OR
  2. 您必须计算rect.right值与右外角度位置(我的情况下为3)之间的差距,并将此值用作硬编码偏移量以进行简单检查。
  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 ()将确保在鼠标悬停时更改光标。