Solved

Writing a simple text string to an edit window

Posted on 2006-07-04
13
567 Views
Last Modified: 2013-11-13
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.
0
Comment
Question by:racurrell
  • 6
  • 4
  • 3
13 Comments
 
LVL 5

Expert Comment

by:bastibartel
ID: 17037610
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
 

Author Comment

by:racurrell
ID: 17038830
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
 
LVL 5

Expert Comment

by:bastibartel
ID: 17039266
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
 
LVL 5

Assisted Solution

by:bastibartel
bastibartel earned 100 total points
ID: 17039365
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
 

Author Comment

by:racurrell
ID: 17039401
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
 
LVL 7

Accepted Solution

by:
yotamsher earned 300 total points
ID: 17040748
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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 5

Expert Comment

by:bastibartel
ID: 17040870
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
 
LVL 7

Expert Comment

by:yotamsher
ID: 17040896
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
 
LVL 5

Expert Comment

by:bastibartel
ID: 17040966
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
 
LVL 7

Expert Comment

by:yotamsher
ID: 17041006
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
 
LVL 5

Expert Comment

by:bastibartel
ID: 17041187
I see - thanks.
Sebastian
0
 

Author Comment

by:racurrell
ID: 17041416
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
 

Author Comment

by:racurrell
ID: 17043129
Thanks To you both,
All working about OK now, just a bit of cleaning up of the code needed.
Rob.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Displaying an arrayList in a listView using the default adapter is rarely the best solution. To get full control of your display data, and to be able to refresh it after editing, requires the use of a custom adapter.
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now