Hungry Mind , Blog about everything in IT - C#, Java, C++, .NET, Windows, WinAPI, ...

CEdit with an ellipsis

Sometimes developers are devoted to absolutely rediculous tasks. Like having an established conception broken for some reason. You spend a lot of time cracking things up to acomplish your mission. Recently I was working on an edit control with an ellipsis if the text does not fit.

I came up with painting the edit in case it's not focused:

class CEllipsisEdit : public CEdit
{
   DECLARE_DYNAMIC(CEllipsisEdit)
 
protected:
   COLORREF GetBkColor() const;
 
protected:
   CBrush m_bkBrush;
 
protected:
   DECLARE_MESSAGE_MAP()
   afx_msg void OnPaint();
 
};
#include "EllipsisEdit.h"
 
IMPLEMENT_DYNAMIC(CEllipsisEdit, CEdit)
 
// CEllipsisEdit message map
 
BEGIN_MESSAGE_MAP(CEllipsisEdit, CEdit)
   ON_WM_PAINT()
END_MESSAGE_MAP()
 
// CEllipsisEdit message handlers
 
COLORREF CEllipsisEdit::GetBkColor() const
{
   if (m_hWnd) {
      const HWND hParentWnd = GetParent()->GetSafeHwnd();
      if (::GetWindowThreadProcessId(hParentWnd, NULL) == ::GetWindowThreadProcessId(m_hWnd, NULL)) {
         CDC dc;
         dc.CreateCompatibleDC(NULL);
         const bool enabled = (GetStyle() & WS_DISABLED) == 0;
         const UINT colorMsg = enabled ? WM_CTLCOLOREDIT : WM_CTLCOLORSTATIC;
 
         ::SendMessage(hParentWnd, colorMsg, reinterpret_cast<WPARAM>(dc.m_hDC), reinterpret_cast<LPARAM>(m_hWnd));
 
         return dc.GetBkColor();
      }
   }
 
   return ::GetSysColor(COLOR_WINDOW);
}
 
void CEllipsisEdit::OnPaint()
{
   if (::GetFocus() == m_hWnd) {
      __super::OnPaint();
      return;
   }
 
   CString text;
   GetWindowText(text);
 
   if (!m_bkBrush.m_hObject)
      m_bkBrush.CreateSolidBrush(GetBkColor());
   
   CPaintDC dc(this);
   
   RECT rc = { 0, 0, 0, 0 };   
   GetClientRect(&rc);
   dc.FillRect(&rc, &m_bkBrush);
   
   GetRect(&rc);
   dc.SetBkMode(TRANSPARENT);
   dc.SelectObject(GetFont());
   dc.DrawText(text, text.GetLength(), &rc, DT_SINGLELINE | DT_NOPREFIX | DT_WORD_ELLIPSIS);
}

There were several problems:

  1. Edit control would paint itself synchronously. No WM_PAINT message is sent, just GetDC(hwnd) and the paint code, no way to sabstitute painting.
  2. Edit control doesn't have non-client area, borders are drawn in client area.
  3. Have to somehow determine text background color.

Synchronous paint seems to be an issue only with focused control. Borders are drawn as usual for unknown reason. Background color shall be determined by sending WM_CTLCOLOREDIT or WM_CTLCOLORSTATIC to parent or just a COLOR_WINDOW system color as a fallback.

Please note that WM_CTLCOLOR-related messages are not sent to parent widows in different threads! Also don't forget to add DT_NOPREFIX flag when invoking DrawText method.

Copyright 2007-2011 Chabster