Simple GDI Problem
-
I have an SDI application, and I'm operating in the OnPaint handler for WM_PAINT messages in my CChildView derived from CWnd. In the CChildView class, I have 2 pointers to class objects I made derived from CObList which are initialized to NULL when the view is constructed. When I open the file, data is read in and one or both lists may be filled with items. Here is some example code:
void CChildView::OnPaint() { CPaintDC dc(this); // device context for paintingif (files != NULL) { if (files != NULL { char * lpszText = new char[32]; sprintf (lpszText, "Files: %u", files->GetCount()); int nTextHeight = dc.DrawText(lpszText, -1, CRect(10, 30, 100, 100), DT_LEFT | DT_SINGLELINE); MessageBox(_T("files detected"), NULL, MB_OK); delete[] lpszText; } else { dc.DrawText(_T("Files: 0"), CRect(10, 30, 100, 100), DT_LEFT); } }
Now, what happens is when I start the app, I am told there are no files which is right. When I open the file, the code runs through and I see the MessageBox displayed but the text that should have been drawn in the line above it doesn't show up on the screen. However, if I were to put a breakpoint on the sprintf line, start the program, load a file, it would break on the line and I were to press F5 to continue executing, the result of DrawText would show up on the screen fine and the message box would pop up too. I've tried to see if I'm doing something wrong or if I'm not doing something I should here and on other GDI tutorial sites but I can't figure out why this behavior exists. Can someone please set me straight? -
I have an SDI application, and I'm operating in the OnPaint handler for WM_PAINT messages in my CChildView derived from CWnd. In the CChildView class, I have 2 pointers to class objects I made derived from CObList which are initialized to NULL when the view is constructed. When I open the file, data is read in and one or both lists may be filled with items. Here is some example code:
void CChildView::OnPaint() { CPaintDC dc(this); // device context for paintingif (files != NULL) { if (files != NULL { char * lpszText = new char[32]; sprintf (lpszText, "Files: %u", files->GetCount()); int nTextHeight = dc.DrawText(lpszText, -1, CRect(10, 30, 100, 100), DT_LEFT | DT_SINGLELINE); MessageBox(_T("files detected"), NULL, MB_OK); delete[] lpszText; } else { dc.DrawText(_T("Files: 0"), CRect(10, 30, 100, 100), DT_LEFT); } }
Now, what happens is when I start the app, I am told there are no files which is right. When I open the file, the code runs through and I see the MessageBox displayed but the text that should have been drawn in the line above it doesn't show up on the screen. However, if I were to put a breakpoint on the sprintf line, start the program, load a file, it would break on the line and I were to press F5 to continue executing, the result of DrawText would show up on the screen fine and the message box would pop up too. I've tried to see if I'm doing something wrong or if I'm not doing something I should here and on other GDI tutorial sites but I can't figure out why this behavior exists. Can someone please set me straight?If you need solution of problem, use CDC* pDC = GetDC(); instead of CPaintDC dc(this);
-
I have an SDI application, and I'm operating in the OnPaint handler for WM_PAINT messages in my CChildView derived from CWnd. In the CChildView class, I have 2 pointers to class objects I made derived from CObList which are initialized to NULL when the view is constructed. When I open the file, data is read in and one or both lists may be filled with items. Here is some example code:
void CChildView::OnPaint() { CPaintDC dc(this); // device context for paintingif (files != NULL) { if (files != NULL { char * lpszText = new char[32]; sprintf (lpszText, "Files: %u", files->GetCount()); int nTextHeight = dc.DrawText(lpszText, -1, CRect(10, 30, 100, 100), DT_LEFT | DT_SINGLELINE); MessageBox(_T("files detected"), NULL, MB_OK); delete[] lpszText; } else { dc.DrawText(_T("Files: 0"), CRect(10, 30, 100, 100), DT_LEFT); } }
Now, what happens is when I start the app, I am told there are no files which is right. When I open the file, the code runs through and I see the MessageBox displayed but the text that should have been drawn in the line above it doesn't show up on the screen. However, if I were to put a breakpoint on the sprintf line, start the program, load a file, it would break on the line and I were to press F5 to continue executing, the result of DrawText would show up on the screen fine and the message box would pop up too. I've tried to see if I'm doing something wrong or if I'm not doing something I should here and on other GDI tutorial sites but I can't figure out why this behavior exists. Can someone please set me straight?The problem is that the area in which you are drawing is not 'invalidated'. Breaking into the debugger has the side-effect of invalidating the entire window and that's why it works fine after that. Whenever you change the info, which by the way should be in your document instead of your view, you need to make the view invalidate the area that needs to be updated. Take a look at this post[^] for more details on how to orchestrate the interaction between the document and its views. Also, instead of this:
char * lpszText = new char[32];
sprintf (lpszText, "Files: %u", files->GetCount());
int nTextHeight = dc.DrawText(lpszText, [...] );
delete[] lpszText;I suggest this:
CString sText;
sText.Format("Files: %u", files->GetCount());
int nTextHeight = dc.DrawText(sText, [...] );It's cleaner, you don't need to worry about how much space to allocate, and you don't risk forgetting to free it. -- jlr http://jlamas.blogspot.com/[^]
-
If you need solution of problem, use CDC* pDC = GetDC(); instead of CPaintDC dc(this);
I was reading about GDI and I believe that's the old way and I figured using CPaintDC was used for a reason. I'll check it out, thanks for the tip.
-
The problem is that the area in which you are drawing is not 'invalidated'. Breaking into the debugger has the side-effect of invalidating the entire window and that's why it works fine after that. Whenever you change the info, which by the way should be in your document instead of your view, you need to make the view invalidate the area that needs to be updated. Take a look at this post[^] for more details on how to orchestrate the interaction between the document and its views. Also, instead of this:
char * lpszText = new char[32];
sprintf (lpszText, "Files: %u", files->GetCount());
int nTextHeight = dc.DrawText(lpszText, [...] );
delete[] lpszText;I suggest this:
CString sText;
sText.Format("Files: %u", files->GetCount());
int nTextHeight = dc.DrawText(sText, [...] );It's cleaner, you don't need to worry about how much space to allocate, and you don't risk forgetting to free it. -- jlr http://jlamas.blogspot.com/[^]
I think I was doing the second way but I must have changed to C-Style strings for some reason, I don't know. I'm using CString's practically everywhere else. I'll take some time and read that link, thanks a lot. edit: I just invalidated the view when the data is changed and it worked like a charm, many thanks. Practically that entire post was very informative, good call.