2016-08-11 8 views
8

컨트롤의 상태와 텍스트에 관계없이 항상 컨트롤 창에 아이콘이 표시된 MFC에서 검색 편집 컨트롤을 만들려고합니다. 몇 년 전에 이런 식으로 글을 썼지 만 잘 작동했지만 코드는 더 이상 Windows 7 이상에서 작동하지 않습니다. (아마도 Vista 일 수도 있지만 시도하지 않았습니다.) 그러면 컨트롤에 표시된 이미지가 입력 영역과 겹치게됩니다 (아래 그림 참조).편집 컨트롤의 검색 아이콘이 입력 영역과 겹침

코드 뒤에 아이디어 :

  • 이 클래스 (즉의 OnPaint에 그림을 처리)
  • 이 아이콘이 오른쪽에 표시되고 편집 영역의 크기에 따라 축소되어 CEdit에서 유래 한 아이콘
  • 크기 조정은 한 줄 편집과 여러 줄 편집의 경우 다르게 수행됩니다. 한 줄의 경우 SetMargins으로 전화를 걸고 여러 줄을 편집 할 경우 SetRect으로 전화합니다. 합니다 (

    void CSymbolEdit::RecalcLayout() 
    { 
        int width = GetSystemMetrics(SM_CXSMICON); 
    
        if(m_hSymbolIcon) 
        { 
         if (GetStyle() & ES_MULTILINE) 
         { 
         CRect editRect; 
         GetRect(&editRect); 
    
         editRect.right -= (width + 6); 
    
         SetRect(&editRect); 
         } 
         else 
         { 
         DWORD dwMargins = GetMargins(); 
         SetMargins(LOWORD(dwMargins), width + 6); 
         } 
        } 
    } 
    

    다음 이미지를 표시하고 하나의 라인에 대한 문제가 편집 :

  • 이 편집 리사이징은 PreSubclassWindow(), OnSize()OnSetFont()

이 편집 입력 크기가 적용되는 방법이다에서인가 더 좋은보기를 위해 이미지가 확대되었습니다). 노란색 배경은 실제 코드에서 강조 표시하기위한 것이며 시스템 색상을 사용하고 있습니다. 한 줄 편집에 텍스트가 있고 입력이 있으면 왼쪽 이미지가 칠해집니다. SetRect이 서식 지정 사각형을 올바르게 설정하는 여러 줄 편집에서는이 문제가 발생하지 않습니다.

enter image description here

이 나는 ​​이미지가 표시되고 편집의 영역을 제거 ExcludeClipRect를 사용하여 시도했다.

CRect rc; 
GetClientRect(rc); 

CPaintDC dc(this); 
ExcludeClipRect(dc.m_hDC, rc.right - width - 6, rc.top, rc.right, rc.bottom); 

DWORD dwMargins = GetMargins(); 
SetMargins(LOWORD(dwMargins), width + 6); 

결과에 아무런 영향을 미치지 않는 것으로 보입니다.

참고로,이 방법은 몇 년 전에 작성되었으며 Windows XP에서 제대로 작동하는 데 사용되었지만 더 이상 올바르지 않습니다.

void CSymbolEdit::OnPaint() 
{ 
    CPaintDC dc(this); 

    CRect rect; 
    GetClientRect(&rect); 

    // Clearing the background 
    dc.FillSolidRect(rect, GetSysColor(COLOR_WINDOW)); 

    DWORD dwMargins = GetMargins(); 

    if(m_hSymbolIcon) 
    { 
     // Drawing the icon 
     int width = GetSystemMetrics(SM_CXSMICON); 
     int height = GetSystemMetrics(SM_CYSMICON); 

     ::DrawIconEx( 
      dc.m_hDC, 
      rect.right - width - 1, 
      1, 
      m_hSymbolIcon, 
      width, 
      height, 
      0, 
      NULL, 
      DI_NORMAL); 

     rect.left += LOWORD(dwMargins) + 1; 
     rect.right -= (width + 7); 
    } 
    else 
    { 
     rect.left += (LOWORD(dwMargins) + 1); 
     rect.right -= (HIWORD(dwMargins) + 1); 
    } 

    CString text; 
    GetWindowText(text); 
    CFont* oldFont = NULL; 

    rect.top += 1; 

    if(text.GetLength() == 0) 
    {  
     if(this != GetFocus() && m_strPromptText.GetLength() > 0) 
     { 
      oldFont = dc.SelectObject(&m_fontPrompt); 
      COLORREF color = dc.GetTextColor(); 
      dc.SetTextColor(m_colorPromptText); 
      dc.DrawText(m_strPromptText, rect, DT_LEFT|DT_SINGLELINE|DT_EDITCONTROL); 
      dc.SetTextColor(color); 
      dc.SelectObject(oldFont); 
     } 
    } 
    else 
    { 
     if(GetStyle() & ES_MULTILINE) 
     CEdit::OnPaint(); 
     else 
     { 
     oldFont = dc.SelectObject(GetFont()); 
     dc.DrawText(text, rect, DT_SINGLELINE | DT_INTERNAL | DT_EDITCONTROL); 
     dc.SelectObject(oldFont); 
     } 
    } 
} 

비슷한 편집 컨트롤의 다른 구현을 살펴 봤는데 모두 동일한 오류가 발생했습니다.

분명히 질문은 컨트롤의 입력 영역에서 이미지 영역을 제외시키는 것입니다. 내가 무슨 일이 일어나고 있는지 생각

+0

'OnPaint' 오버라이드가 Edit 컨트롤의 페인트 루틴과 싸우고 있습니다. 'CPaintDC'를 사용하여 컨트롤을 수동으로 페인트합니다. 때로는'CEdit :: OnPaint'를 호출하고, 다시 CPaintDC를 호출하고 클라이언트 영역을 다시 칠하는 기본 처리를합니다. Edit 컨트롤의 초점이 맞지 않을 때 또는 페인트 메시지가 수신되면이 작업은 실패합니다. –

+0

'CEdit :: OnPaint()'는 다중 편집에 대해서만 호출됩니다. 이것은 내 관심사가 아닙니다. 단일 줄 편집 컨트롤 만 사용하고 있습니다. 이 경우 경계를 올바르게 설정했기 때문에 여러 줄 편집을 언급했습니다. –

+0

'CWnd :: OnCtlColor()'를 오버라이드하고 거기에서'ExcludeClipRect()'를 호출하면 어떨까요? 빠른 테스트와 함께 여기서 제대로 작동하지만 MFC가없는 것 같습니다. 자신의 물건을 보여주기 위해'OnPaint()'에서 다시 클리핑을 변경해야 할 수도 있습니다. – isanae

답변

0

는 그 편집 상자에 WM_ERASEBKGND를 전송 CPaintDC 전화 BeginPaint(). 나는 그것을 무시할 수 없었기 때문에 아마도 내부의 STATIC 창으로 전송되고있는 것일까? 확실하지 않다. EDITBeginPaint() 또는 자신의 WM_PAINT 처리기 중 하나에서 전체 클라이언트 영역에 클리핑 영역을 다시 설정 때문에 아무것도하지 않습니다 당신의 OnPaint() 핸들러에서 ExcludeClipRect()를 호출

.

그러나 EDIT은 자신을 그리기 직전에 WM_CTRCOLOREDIT을 부모에게 보냅니다. 그러나 클리핑 영역을 설정 한 후에는 외관상으로는 그려집니다. 그래서 ExcludeClipRect() 번으로 전화 할 수 있습니다. 일반적인 컨트롤의 향후 버전에서 변경 될 수있는 구현 세부 정보와 비슷합니다. 실제로 이미 그렇게 된 것 같습니다.

LRESULT CALLBACK wnd_proc(HWND h, UINT m, WPARAM wp, LPARAM lp) 
{ 
    switch (m) 
    { 
     case WM_CTLCOLOREDIT: 
     { 
      const auto dc = (HDC)wp; 
      const auto hwnd = (HWND)lp; 

      RECT r; 
      GetClientRect(hwnd, &r); 

      // excluding the margin, but not the border; this assumes 
      // a one pixel wide border 
      r.left = r.right - some_margin; 
      --r.right; 
      ++r.top; 
      --r.bottom; 

      ExcludeClipRect(dc, r.left, r.top, r.right, r.bottom); 

      return (LRESULT)GetStockObject(DC_BRUSH); 
     } 
    } 

    return ::DefWindowProc(h, m, wp, lp); 
} 

내가 다음 WM_PAINT에 내 자신의 아이콘을 그립니다 EDIT 윈도우를 서브 클래 싱하고 나는 'didn를 수 있도록 메시지를 전달 :

내가 Windows 7에서 MFC없이 빠른 테스트를했다, 여기 내 윈도우 프로 시저의 다른 모든 것을 그려야합니다. 내가 BeginPaint()EndPaint() 경계가 그려되지 않기 때문에 WM_PAINT에 (A CPaintDC을 구성하는 것과 동일)를 호출 할 수

LRESULT CALLBACK edit_wnd_proc(
    HWND h, UINT m, WPARAM wp, LPARAM lp, 
    UINT_PTR id, DWORD_PTR data) 
{ 
    switch (m) 
    { 
     case WM_PAINT: 
     { 
      const auto dc = GetDC(h); 

      // draw an icon 

      ReleaseDC(h, dc); 
      break; 
     } 
    } 

    return DefSubclassProc(h, m, wp, lp); 
} 

참고. 나는 그것이 BeginPaint()을 두 번 호출 (수동으로 한 번, EDIT에 의해 한번)하고 WM_ERASEBKGND을 처리하는 것과 관련이 있다고 생각합니다. YMMV, 특히 MFC 사용

마지막으로, 나는 바로 EDIT를 만든 후 여백을 설정 :

SendMessage(
    e, EM_SETMARGINS, 
    EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELPARAM(0, margin)); 

또한 다시하면 시스템 글꼴 변경 여백을 업데이트해야 할 수도 있습니다.