CEdit::CharFromPos -- trying to write a bugfix, please help (having problems with tabs) 
Author Message
 CEdit::CharFromPos -- trying to write a bugfix, please help (having problems with tabs)

Hi groupies,

My problem is that 'int CEdit::CharFromPos(CPoint)' returns the charachter
index in the low-order word. So the maximum return value is the maximum
value of a WORD (equivalent to unsigned short). If the CEdit control
contains more charachters than 2^(8*sizeof(unsigned short))-1 = 65535, the
returned index from CEdit::CharFromPos is invalid.

So I'm trying to write a workaround. But I'm having problems taking tabs
into account. If a line at a certain point doesn't contain tabs, this
workaround returns a correct charachter index. But things get messed up if
the line contains tab charachters. In that case the returned charachter
index is in the correct line, but not on the correct position within that
line. I use BOOL CEdit::SetTabStops(const int&) to set the tab stops.

The workaround is posted at the bottom of the post. The lines marked with
(*) deal with tabs and do not produce correct results. Can anyone suggest a
strategy to calculate the length of a line containing tabs correctly? If
anybody knows of an existing workaround that works, please let me know.

Thanks,
Tom.

#include <cmath> // floor()

UINT CEditCtrl::CharFromPos(CPoint pt)
{
 CRect rect;
 GetClientRect(&rect);

 UINT char_ind = 0;
 if(rect.PtInRect(pt))
 {
  CClientDC client_dc( this );
    // Select stock font to DC, cos I'm actually doing this from an ActiveX
control
  CFont* old_font = SelectStockFont(&client_dc);
  TEXTMETRIC text_metric;
  client_dc.GetOutputTextMetrics(&text_metric);
  long height_row = client_dc.GetOutputTextExtent(" ",1).cy +
text_metric.tmExternalLeading;
  long line_count = GetLineCount();
  long left_margin = LOWORD( GetMargins() );

  // line index for point, top margin is 1 pixel
  long line_ind = (pt.y!=0) ? ( GetFirstVisibleLine() + floor((pt.y - 1) /
double(height_row)) ) : 0;
  long pos = 0;
  if(line_ind>line_count-1)
   line_ind = line_count-1;

  if(pt.x >= left_margin)
  {
   CString line = GetTextAtInt(line_ind); // Get Text at line index, see
below for definition
   if(!line.IsEmpty())
   {
    LPCTSTR line_= line;
    long inter_char_pxl = client_dc.GetTextCharacterExtra();
    long x_pos = left_margin;
    long tab_pxls = client_dc.GetOutputTextExtent("\t", 1).cx; // (*)
    for(; x_pos<pt.x && pos!=line.GetLength(); ++pos)
     if(line_[pos]=='\t')
      x_pos += tab_pxls - ((x_pos - left_margin) % tab_pxls); // (*)
     else
      x_pos += client_dc.GetOutputTextExtent(line_[pos], 1).cx +
inter_char_pxl;

    if(x_pos>=pt.x)
     --pos;
   }
  }
  client_dc.SelectObject(old_font);
  char_ind = LineIndex(line_ind) + pos; // Calculate charachter index from
[line_index, pos]
 }
 return char_ind;

Quote:
}

CString CEditCtrl::GetTextAtInt(long line_index)
{
 CString ret;

 long buf_size = LineLength( LineIndex(line_index) ) + 1; // +1 for
terminating \0 charachter
 LPTSTR line_buf  = ret.GetBuffer(buf_size);
 int cc = GetLine((line_index == -1) ? LineFromChar() : line_index,
line_buf, buf_size);
 ASSERT(cc>=0 && cc<buf_size);
 line_buf[cc] = '\0';

 ret.ReleaseBuffer();
 return ret;

Quote:
}



Sat, 10 Sep 2005 18:16:05 GMT  
 CEdit::CharFromPos -- trying to write a bugfix, please help (having problems with tabs)
Hi,

I think CEdit can only have 65536 characters in it anyway so your code
may be redundant.

There are articles in MSDN that talk about using a CRichEditCtrl
instead as these can have many more characters (I'm guessing 2^32
rather than 2^16).

I couldn't find an equivalent of CharFromPos() for CRichEditCtrl, but
I hope this helps... give it a look maybe :o)

Good luck :o)
Mike Youell.

Quote:

> Hi groupies,

> My problem is that 'int CEdit::CharFromPos(CPoint)' returns the charachter
> index in the low-order word. So the maximum return value is the maximum
> value of a WORD (equivalent to unsigned short). If the CEdit control
> contains more charachters than 2^(8*sizeof(unsigned short))-1 = 65535, the
> returned index from CEdit::CharFromPos is invalid.

> So I'm trying to write a workaround. But I'm having problems taking tabs
> into account. If a line at a certain point doesn't contain tabs, this
> workaround returns a correct charachter index. But things get messed up if
> the line contains tab charachters. In that case the returned charachter
> index is in the correct line, but not on the correct position within that
> line. I use BOOL CEdit::SetTabStops(const int&) to set the tab stops.

> The workaround is posted at the bottom of the post. The lines marked with
> (*) deal with tabs and do not produce correct results. Can anyone suggest a
> strategy to calculate the length of a line containing tabs correctly? If
> anybody knows of an existing workaround that works, please let me know.

> Thanks,
> Tom.

> #include <cmath> // floor()

> UINT CEditCtrl::CharFromPos(CPoint pt)
> {
>  CRect rect;
>  GetClientRect(&rect);

>  UINT char_ind = 0;
>  if(rect.PtInRect(pt))
>  {
>   CClientDC client_dc( this );
>     // Select stock font to DC, cos I'm actually doing this from an ActiveX
> control
>   CFont* old_font = SelectStockFont(&client_dc);
>   TEXTMETRIC text_metric;
>   client_dc.GetOutputTextMetrics(&text_metric);
>   long height_row = client_dc.GetOutputTextExtent(" ",1).cy +
> text_metric.tmExternalLeading;
>   long line_count = GetLineCount();
>   long left_margin = LOWORD( GetMargins() );

>   // line index for point, top margin is 1 pixel
>   long line_ind = (pt.y!=0) ? ( GetFirstVisibleLine() + floor((pt.y - 1) /
> double(height_row)) ) : 0;
>   long pos = 0;
>   if(line_ind>line_count-1)
>    line_ind = line_count-1;

>   if(pt.x >= left_margin)
>   {
>    CString line = GetTextAtInt(line_ind); // Get Text at line index, see
> below for definition
>    if(!line.IsEmpty())
>    {
>     LPCTSTR line_= line;
>     long inter_char_pxl = client_dc.GetTextCharacterExtra();
>     long x_pos = left_margin;
>     long tab_pxls = client_dc.GetOutputTextExtent("\t", 1).cx; // (*)
>     for(; x_pos<pt.x && pos!=line.GetLength(); ++pos)
>      if(line_[pos]=='\t')
>       x_pos += tab_pxls - ((x_pos - left_margin) % tab_pxls); // (*)
>      else
>       x_pos += client_dc.GetOutputTextExtent(line_[pos], 1).cx +
> inter_char_pxl;

>     if(x_pos>=pt.x)
>      --pos;
>    }
>   }
>   client_dc.SelectObject(old_font);
>   char_ind = LineIndex(line_ind) + pos; // Calculate charachter index from
> [line_index, pos]
>  }
>  return char_ind;
> }

> CString CEditCtrl::GetTextAtInt(long line_index)
> {
>  CString ret;

>  long buf_size = LineLength( LineIndex(line_index) ) + 1; // +1 for
> terminating \0 charachter
>  LPTSTR line_buf  = ret.GetBuffer(buf_size);
>  int cc = GetLine((line_index == -1) ? LineFromChar() : line_index,
> line_buf, buf_size);
>  ASSERT(cc>=0 && cc<buf_size);
>  line_buf[cc] = '\0';

>  ret.ReleaseBuffer();
>  return ret;
> }



Mon, 12 Sep 2005 15:38:10 GMT  
 CEdit::CharFromPos -- trying to write a bugfix, please help (having problems with tabs)

Quote:
> Hi,

> I think CEdit can only have 65536 characters in it anyway so your code
> may be redundant.

No true. Documentation states clearly that the maximum length is 0x7FFFFFFF
for single line and 0xFFFFFFFF for multiple line controls (CEdit used in
VC6SP at least).

Quote:
> There are articles in MSDN that talk about using a CRichEditCtrl
> instead as these can have many more characters (I'm guessing 2^32
> rather than 2^16).

Mmm, very suspect. You should really reread the docu (especially docu for
message EM_LIMITTEXT). Besides it is definitely possible to get that much
charachters in a CEdit control, because I had about 1 mega charachters in an
edit control (to test).

Quote:
> I couldn't find an equivalent of CharFromPos() for CRichEditCtrl, but
> I hope this helps... give it a look maybe :o)
> Good luck :o)
> Mike Youell.

Thank you. Now actually I'm trying the following out. I read in the
documentation for CEdit::SetTabStops(const int&), that the value passed to
SetTabStops is in dialog units. So I'm now trying the following strategy
from a regular subclassed CEdit:

    // Somewhere in my code (example) to set the tab stops
    CMyEditCtrl* pMyEdit = GetMyEditCtrl();
    pMyEdit->SetTabStops( MYTAB_STOPS ); // MYTAB_STOPS in dialog units!!!

    // Somewhere in my CharFromPos_ workaround method:
    CClientDC parent_dc( GetParent() );
    parent_dc.SelectObject( GetParent()->GetFont() );

    // Get size for total alphabet in parent font
    CSize cs_alphabet =
parent_dc.GetTextExtent(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
wxyz"), 52);

    // Average of text extents of alphabet, round up
    long average_cx_alphabet = (cs_alphabet.cx + 26) / 52;

    // Convert from dialog units (MYTAB_STOPS) to pixels (tab_pxls)
    long tab_pxls = (MYTAB_STOPS * average_cx_alphabet) / 4;

This strategy gives me the correct number of pixels. So it is easy for a
regular subclassed control, but difficult from an ActiveX control based on
an Edit control (the thing I am actually working on). I cannot get to the
parent font. The documentation states that AmbientFont is to be used, but
using that font gives incorrect results.

But before asking this I will repost my fix, with yet another problem
(*sigh*). Now the height of a row (height_row) is incorrect for some fonts.

Cya
Tom.



Mon, 12 Sep 2005 18:05:44 GMT  
 CEdit::CharFromPos -- trying to write a bugfix, please help (having problems with tabs)

Quote:


[...]
> Mmm, very suspect. You should really reread the docu (especially docu for
> message EM_LIMITTEXT). Besides it is definitely possible to get that much
> charachters in a CEdit control, because I had about 1 mega charachters in
an
> edit control (to test).

[...]

Should be EM_SETLIMITTEXT.

Tom.



Mon, 12 Sep 2005 18:07:08 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. CEdit::CharFromPos workaround: almost there ... one more problem

2. CEdit::CharFromPos failing for large text, need help

3. Please help wit client window in MFC.

4. Please help-still having problems with bubble sort

5. I keep having problems with * operator, please help!

6. Raw beginner having problems - please help

7. Workaround for CEdit::CharFromPos (final!)

8. CEdit::CharFromPos

9. Stack problems wit C/C++: Help

10. PLEASE HELP CEDIT PROBLEM

11. Having problems incorporating pre-written code into my program

12. Having problems incorporating pre-written code into my program

 

 
Powered by phpBB® Forum Software