Writing a simple text string to an edit window

This appears to be a trivial question but I cannot get it to work correctly. Please could someone explain why I get no text appearing in the edit window?  The caret is there OK in teh correct window and all seems normal, just no text showing.  What else is needed to make it work please?  I am using ATL/WTL and all the variables seem OK. (declaration of all variables is elsewhere in the class, just ommitted for brevity, str included just for testing)

      // Select a fixed-width system font, and get its text metrics.

      hdc = m_DepthStatus.GetDC();
      SelectObject(hdc,
            GetStockObject(SYSTEM_FIXED_FONT));
      GetTextMetrics(hdc, &tm);
      m_DepthStatus.ReleaseDC(hdc);

      // Save the avg. width and height of characters.
      nCharX = tm.tmAveCharWidth;
      nCharY = tm.tmHeight;

      m_DepthStatus.GetClientRect(&nWindow);      //Get the window size info

      // Determine the width of the client area, in pixels
      // and in number of characters.
 
      nWindowX = nWindow.right;
      nWindowCharsX = max(1, nWindowX/nCharX);
 
      // Determine the height of the client area, in
      // pixels and in number of characters.
 
      nWindowY = nWindow.bottom;
      nWindowCharsY = max(1, nWindowY/nCharY);
 
      // Clear the buffer that holds the text input.
 
      if (pTextMatrix != NULL)
            free(pTextMatrix);
 
      // If there is enough memory, allocate space for the
      // text input buffer.
 
      pTextMatrix = (char*) malloc(nWindowCharsX * nWindowCharsY);
 
      if (pTextMatrix == NULL)
            MessageBox("Not enough memory available for the Text Buffer.");
      else
            for (y = 0; y < nWindowCharsY; y++)
            for (x = 0; x < nWindowCharsX; x++)
                  TEXTMATRIX(x, y) = ' ';

      // Move the caret to the origin.
      // Create a grey caret.
            m_DepthStatus.CreateGrayCaret(nCharX,nCharY);

      SetCaretPos(nCaretPosX * nCharX,
            nCaretPosY * nCharY);
      m_DepthStatus.ShowCaret();

      // Draw all the characters in the buffer, line by line.
      hdc = m_DepthStatus.BeginPaint(&ps);
 
      SelectObject(hdc,
            GetStockObject(SYSTEM_FIXED_FONT));

      char* str;                          // Debug line
      str = new char[12];           // Debug line
      strcpy(str, "Test String");   // Debug line
 
      for (y = 0; y < nWindowCharsY; y++)
            TextOut(hdc, 0, y * nCharY, str,
                  nWindowCharsX);

      m_DepthStatus.EndPaint(&ps);

Thanks
Rob.
racurrellAsked:
Who is Participating?
 
yotamsherConnect With a Mentor Commented:
Hi racurrell

quite a refereshing question, WTL is cool, and is bringing us back to the basics of GDI

below is a working code, with my comments inside (beginning with \\Yotam: )
your main problem was regarding the HDC, which you were taking through BeginPaint
see Microsoft documentation at :
      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_7b78.asp

stating: "...An application should not call BeginPaint except in response to a WM_PAINT message..."

anyway enjoy and good luck

Yotam

LRESULT CBlaDlg::OnBnClickedButton2(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
      CWindow m_DepthStatus = GetDlgItem(IDC_STATIC6);
      int nWindowX, nWindowY, nWindowCharsX, nWindowCharsY      ;
      int nCharX, nCharY, nCaretPosX = 0, nCaretPosY = 0;
      RECT nWindow;
      PAINTSTRUCT ps;
      TEXTMETRIC      tm;
      char * pTextMatrix = NULL;
      int x;
      int y;
      HDC hdc;

      // Select a fixed-width system font, and get its text metrics.

      hdc = m_DepthStatus.GetDC();
      SelectObject(hdc,
            GetStockObject(SYSTEM_FIXED_FONT));
      GetTextMetrics(hdc, &tm);
//Yotam: Use this HDC for the actual painting, don't release it here
      //      m_DepthStatus.ReleaseDC(hdc);

      // Save the avg. width and height of characters.
      nCharX = tm.tmAveCharWidth;
      nCharY = tm.tmHeight;

      m_DepthStatus.GetClientRect(&nWindow);     //Get the window size info

      // Determine the width of the client area, in pixels
      // and in number of characters.

      nWindowX = nWindow.right;
      nWindowCharsX = max(1, nWindowX/nCharX);

      // Determine the height of the client area, in
      // pixels and in number of characters.

      nWindowY = nWindow.bottom;
      nWindowCharsY = max(1, nWindowY/nCharY);

      // Clear the buffer that holds the text input.
/*
Yotam: I guess this block is for the real thing and  later you print these chars in the window

      if (pTextMatrix != NULL)
            free(pTextMatrix);

      // If there is enough memory, allocate space for the
      // text input buffer.
      pTextMatrix = (char*) malloc(nWindowCharsX * nWindowCharsY);

      if (pTextMatrix == NULL)
            MessageBox("Not enough memory available for the Text Buffer.");
      else
            for (y = 0; y < nWindowCharsY; y++)
                  for (x = 0; x < nWindowCharsX; x++)
                        TEXTMATRIX(x, y) = ' ';
*/
      // Move the caret to the origin.
      // Create a grey caret.
      m_DepthStatus.CreateGrayCaret(nCharX,nCharY);

      SetCaretPos(nCaretPosX * nCharX,
            nCaretPosY * nCharY);
      m_DepthStatus.ShowCaret();

      // Draw all the characters in the buffer, line by line.
// Yotam: here is the big problem look at Microsoft documentation at:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_7b78.asp
// You should not call BeginPaint outside the handling of WM_PAINT
// If you debug and look at the data in ps you see it is all NULL

      HDC hdc2 = m_DepthStatus.BeginPaint(&ps);

      SelectObject(hdc,
            GetStockObject(SYSTEM_FIXED_FONT));
// Yotam: here you need to set the color of you text
      SetTextColor( hdc, RGB(0,0,0));
      SetBkColor( hdc, RGB(0,255,0)); // Yotam: well if you realy want the feeling of a terminal...
      SetB
      char* str;                          // Debug line
      str = new char[12];           // Debug line
      strcpy(str, "Test String");   // Debug line

      nCaretPosX = 11;
      for (y = 0; y < nWindowCharsY; y++)
      {
// Yotam: here is another important one, the last parameter to textout should be " Specifies the length of the string pointed to by lpString"
            TextOut(hdc, 0, y * nCharY, str, 11);
            nCaretPosY = y;
            SetCaretPos(nCaretPosX * nCharX,
                  nCaretPosY * nCharY); //Yotam: here I move your cursor with the text
      }

      m_DepthStatus.EndPaint(&ps);

      return 0;
}
0
 
bastibartelCommented:
Hi there,

I am trying to compile your code...

DepthStatus.GetDC() should return a CDC* not a HDC
but you are using hdc as if it were a HDC. Am I missing something

Cheers,
Sebastian
0
 
racurrellAuthor Commented:
Hi Sebastian,
I tried changing the HDC into CDC and it compiled OK but still gave the same result, I have included my variable declaration code fragment for you to look at as well so you now have just about all of the routine except the storage locations in the cpp file, it still has the original HDC declaration that is now commented out as you can see.  Please advise if this is incorrect?

The code was taken from the microsoft site, and I have tried to port it to ATL/WTL, I am not very experienced as you probably realise at Windows programming.

HINSTANCE hinst;                  // current instance
HBITMAP hCaret;                  // caret bitmap
//HDC hdc;                        // device context
CDC cdc;
PAINTSTRUCT ps;                  // client area paint info
static char *pTextMatrix;            // points to text matrix
static int  nCharX,                  // width of char. in logical units
            nCharY,                  // height of char. in logical units
            nWindowX,                  // width of client area
            nWindowY,                  // height of client area
            nWindowCharsX,            // width of client area in chars
            nWindowCharsY,            // height of client area in chars
            nCaretPosX,                  // x-position of caret
            nCaretPosY;                  // y-position of caret
static UINT uOldBlink;                  // previous blink rate
int x, y;                        // coordinates for text matrix
TEXTMETRIC tm;                  // font information

RECT nWindow;                  /Window coordinates.

Any further thoughts please?
Cheers,
Rob.
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
bastibartelCommented:
Hi Rob,

it's quite late here already and I will look at the code tomorrow.
But I was wandering - you want to display text in an CEdit control ? If so, why not just Use CEdit::SetWindowText().
At first glance it looks like you are trying to paint over the Edit window. Ignore the question, if you have good reasons to do it manually - just asking without having looked very thoroughly yet.

Cheers,
Sebastian
0
 
bastibartelConnect With a Mentor Commented:
Try this ..

{
//** I used CEdit resource IDC_EDIT1
   //CWnd &m_DepthStatus = *GetDlgItem(IDC_EDIT1);

   TEXTMETRIC tm;
    CDC* pDC = m_DepthStatus.GetDC();
    pDC->SelectObject(GetStockObject(SYSTEM_FIXED_FONT));
    pDC->GetTextMetrics(&tm);
    //m_DepthStatus.ReleaseDC(pDC);  //* is released further down

     // Save the avg. width and height of characters.
     int nCharX = tm.tmAveCharWidth;
     int nCharY = tm.tmHeight;

     CRect nWindow;
     m_DepthStatus.GetClientRect(&nWindow);     //Get the window size info

     // Determine the width of the client area, in pixels
     // and in number of characters.
 
    int nWindowX = nWindow.right;
    int nWindowCharsX = max(1, nWindowX/nCharX);
 
     // Determine the height of the client area, in
     // pixels and in number of characters.
 
    int nWindowY = nWindow.bottom;
    int nWindowCharsY = max(1, nWindowY/nCharY);
 
     // Clear the buffer that holds the text input.
     // If there is enough memory, allocate space for the
     // text input buffer.

/* what is this for ? pTextMatrix is never used
    char *pTextMatrix;
     pTextMatrix = (char*) malloc(nWindowCharsX * nWindowCharsY);
 
     if (pTextMatrix == NULL)
          MessageBox("Not enough memory available for the Text Buffer.");
     else
          for (int y = 0; y < nWindowCharsY; y++)
          for (int x = 0; x < nWindowCharsX; x++)
               pTextMatrix[x][y] = ' ';
*/
     // Move the caret to the origin.
     // Create a grey caret.
    int nCaretPosX(10), nCaretPosY(10);
    m_DepthStatus.CreateGrayCaret(nCharX,nCharY);

     SetCaretPos(CPoint(nWindowCharsX * nCharX, nWindowCharsY * nCharY));
     m_DepthStatus.ShowCaret();

     // unneccessary ...
     // Draw all the characters in the buffer, line by line.
     // PAINTSTRUCT ps;    
     // pDC = m_DepthStatus.BeginPaint(&ps);
 
     pDC->SelectObject(GetStockObject(SYSTEM_FIXED_FONT));
       pDC->SetTextColor(RGB(255,0,0));

    //* shortened a bit ..
     char str[] = {"Test String"};                       // Debug line
   
     for (int y = 0; y < nWindowCharsY; y++)
         pDC->TextOut(0, y * nCharY, str,
               nWindowCharsX);

     // m_DepthStatus.EndPaint(&ps);
     m_DepthStatus.ReleaseDC(pDC);

}

Plz get back to me .. there is some cleanup to be done after painting

Cheers
Sebastian
0
 
racurrellAuthor Commented:
Hello Sebastian,
 I want to use the window as a continuously updated display of received telemetry data from an external device connected via the serial port so I only want to update the area of the window where the new data is being written, similar to the way it used to be done on an old fashioned VDU with a memory mapped display, which was very easy to do as screen formatting was built into the programming languages available in the old days.

I originally wrote out the headings on initilization using CEdit::SetWindowText() as you suggest, which worked OK and was originally doing all the data output that way, replacing the whole string on each refresh cycle but had trouble keeping the very long string format correct and also ran into what I think were timing problems as the display window is one of two quite large windows both of which are receiving a lot of data via fast updates (which are also being logged to disk) so I did not want the timing overhead of updating both the screens on each data refresh cycle.  It may not be a problem but I think it could be when both windows are fully active.

Hence the reason to try to adapt what is effectively a simple text editor program a bit like notepad for my display widows using a fixed width text font.  There are several of these about on the Internet but they all seemed to use MFC, which I do not much like and do not want to use for this program.

Your help is appreciated.  Thank you.

Cheers,
Rob.
0
 
bastibartelCommented:
Hi there,

what is the difference to the code I posted ?
Except for the last parameter (11) toTextOut()

oh, and plus:
CWnd::GetDlgItem() return a CWnd*
CWnd::GetDC() return a CDC*
... and this code does not compile on my machine

 @Rob:
Are you using CWindow as base class rather than CWnd ?
*confused*

Cheers & good morning,
Sebastian
0
 
yotamsherCommented:
Hi Sebastian

oops sorry I just got in and posted my answer this morning, after programming it last night, and did not see your post.

In principle your code is fine, just that all this CWnd and CDC stuff is MFC, while Rob was asking for an ATL/WTL solution.
I also pointed for the reason for the problems.
but I agree, that your answer could lead Rob to the solution.

Yotam
0
 
bastibartelCommented:
Yeah you are right .. I couldn't tell by the code from the initial posting, what types he was using.

So Yotam, how is it then...?
like: CWindow m_DepthStatus = CWindow::GetDlgItem(IDC_STATIC6);
or    CWindow m_DepthStatus = CWnd::GetDlgItem(IDC_STATIC6);

cause both do not compile due to documentation.

Cheeers,
Sebastian
0
 
yotamsherCommented:
the point is that my dialog class is of the ATL type CAxDialogImpl:

class CBlaDlg :
      public CAxDialogImpl<CBlaDlg>
{...

and this line is actualy calling the class member function (as if it was this->GetDlgItem)

in your code just call:

CWindow m_DepthStatus( ::GetDlgItem( m_hWnd, IDC_STATIC6) );

Yotam
0
 
bastibartelCommented:
I see - thanks.
Sebastian
0
 
racurrellAuthor Commented:
Thanks Guys,
Now we are really getting somewhere.

Yotam, your code compiles fine under WTL and works OK in a test app that I knocked up to try it out in, this used both a static text box and an edit box for the display, however, it does not yet work in my app but that will be due to some old junk code that I have still left uncommented out somewhere.

I realised that your version used MFC Sebastian but as Yotam noted I am using WTL which will not compile your code as it stands.  I have increased the points total and will split them between you when I tick the accept box later on today.  I was amused by your idea of making the background green Yotam, thats really retro-cool.  Not too sure that my client would appreciate it though.

Thanks Yotam, you're a real cool Guy!

Another problem was that I had declared the display as a CEdit rather than as a CWIndow.  You are correct Yotam in your assumption that the commented out text buffer is part of the real app.

Cheers,
Rob.
0
 
racurrellAuthor Commented:
Thanks To you both,
All working about OK now, just a bit of cleaning up of the code needed.
Rob.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.