Re: Exiting a Do-While loop
MikeAThon:
Your explanation makes perfect sense; I thought time() incremented every millisecond like GetTickCount().
After the corrections my GraphicObjects behave as they should. :D
I have two radio buttons that select either conventional graphics or double-buffer graphics,
similar to your menu selection for same in your double-buffer demo.
My conventional display is OK.
Major problems with double-buffer display. I get a few "splashes" of something happening in the "PictureBox",
but for the most part it stays empty.
The computer becomes very sluggish (almost unresponsive to mouse movements etc), but as soon as I select conventional,
graphics appear again, and the computer operates properly.
I used the same code for double buffering as I did for conventional display, with the addition of a few extra steps required for BitBlt.
I had coded this before you posted your demo, so variable names are different, but as far as I can see I have done as you.
my hdcBuff -> your memDC
my bmpBuff -> your hBitmap
Here is my code to display graphics for both methods; maybe you can spot something I can't?
Code:
void UpdateFrame()
{
int i;
for (i=0; i<=19; i++)
{
MoveGraphicObject(GraphicObject[i]);
}
switch ( DisplayMethod )
{
case 0: //conventional method
for (i=0; i<=19; i++)
{
HDC hdc;
HPEN myPen;
HBRUSH myBrush;
hdc = GetDC(hChild);
myPen = CreatePen(PS_SOLID, 1, GraphicObject[i].color);
myBrush = CreateSolidBrush(GraphicObject[i].color);
SelectObject(hdc, myPen);
SelectObject(hdc, myBrush);
Ellipse(hdc,
GraphicObject[i].x1,
GraphicObject[i].y1,
GraphicObject[i].x1+abs(GraphicObject[i].radius),
GraphicObject[i].y1+abs(GraphicObject[i].radius));
DeleteObject(myBrush);
DeleteObject(myPen);
ReleaseDC(hChild, hdc);
}
break;
case 1: //back-buffer method
for (i=0; i<=19; i++)
{
HDC hdc;
HPEN myPen;
HBRUSH myBrush;
// Create a compatible DC
hdcBuff=CreateCompatibleDC(hdcChild);
// Create a bitmap big enough to hold client rectangle
bmpBuff=CreateCompatibleBitmap(hdcChild,
rc.right-rc.left,
rc.bottom-rc.top);
// Select the bitmap into the off-screen DC
bmpMain = (HBITMAP)SelectObject(hdcBuff, bmpBuff);
hdc=hdcBuff;
myPen = CreatePen(PS_SOLID, 1, GraphicObject[i].color);
myBrush = CreateSolidBrush(GraphicObject[i].color);
SelectObject(hdc, myPen);
SelectObject(hdc, myBrush);
Ellipse(hdc,
GraphicObject[i].x1,
GraphicObject[i].y1,
GraphicObject[i].x1+abs(GraphicObject[i].radius),
GraphicObject[i].y1+abs(GraphicObject[i].radius));
DeleteObject(myBrush);
DeleteObject(myPen);
//ReleaseDC(hChild, hdc);
//DeleteDC(hdcBuff);
}
//copy the back-buffer to the "PictureBox"
long ret;
ret = BitBlt(hdcChild,
0,
0,
(rc.right-rc.left),
(rc.bottom-rc.top),
hdcBuff,
0,
0,
SRCCOPY);
DeleteObject(bmpBuff);
DeleteDC(hdcBuff);
break;
}
}
Re: Exiting a Do-While loop
I've corrected my program to the point that it runs without 'hanging', however selecting the double-buffer radio button draws no graphics in the "picturebox".
If I change Ellipse(hdcBuff, ... to Ellipse(hdcChild, ... in case 1: //back-buffer method
Circles are drawn to the picturebox but they are all white with black
outlines, and since the "picturebox" has a black background, I'm wondering if this is why they can't be seen...
or,
am I not Deleteing and Selecting the Pens and Brushes properly, because why are all the circles black and white?
If I select the conventional radio button, all 20 multi-color circles immdiately appear.
The code for conventional and double-buffer are identical except for the hdc used
(hdcChild for the first and hdcBuff for the second).
I add one additional line to the back-buffer method... ret = BitBlt(hdcChild, ...
Here is the revised UpdateFrame code:
Code:
void UpdateFrame()
{
HDC hdc;
HPEN myPen;
HBRUSH myBrush;
HPEN origPen;
HBRUSH origBrush;
int i;
for (i=0; i<=19; i++)
{
MoveGraphicObject(GraphicObject[i]);
}
switch ( DisplayMethod )
{
case 0: //conventional method
for (i=0; i<=19; i++)
{
myPen = CreatePen(PS_SOLID, 1, GraphicObject[i].color);
myBrush = CreateSolidBrush(GraphicObject[i].color);
SelectObject(hdcChild, myPen);
SelectObject(hdcChild, myBrush);
Ellipse(hdcChild,
GraphicObject[i].x1,
GraphicObject[i].y1,
GraphicObject[i].x1+abs(GraphicObject[i].radius),
GraphicObject[i].y1+abs(GraphicObject[i].radius));
DeleteObject(myPen);
DeleteObject(myBrush);
}
break;
case 1: //back-buffer method
for (i=0; i<=19; i++)
{
myPen = CreatePen(PS_SOLID, 1, GraphicObject[i].color);
myBrush = CreateSolidBrush(GraphicObject[i].color);
SelectObject(hdcBuff, myPen);
SelectObject(hdcBuff, myBrush);
//use hdcChild below and see that white circles are being drawn
Ellipse(hdcBuff,
GraphicObject[i].x1,
GraphicObject[i].y1,
GraphicObject[i].x1+abs(GraphicObject[i].radius),
GraphicObject[i].y1+abs(GraphicObject[i].radius));
DeleteObject(myBrush);
DeleteObject(myPen);
}
//copy the back-buffer to the "PictureBox"
long ret;
ret = BitBlt(hdcChild,
0,
0,
(rc.right-rc.left),
(rc.bottom-rc.top),
hdcBuff,
0,
0,
SRCCOPY);
break;
}
}
And here is the initialization I do in the WM_CREATE handler of the MAIN window:
Code:
// Get size of client rectangle
GetClientRect(hChild, &rc);
// Create a compatible DC
hdcBuff=CreateCompatibleDC(hdcChild);
// Create a bitmap big enough to hold client rectangle
bmpBuff=CreateCompatibleBitmap(hdcChild,
rc.right-rc.left,
rc.bottom-rc.top);
// Select the bitmap into the off-screen DC
bmpMain = (HBITMAP)SelectObject(hdcBuff, bmpBuff);
I am a very patient person, but I think I've run out of ideas as to how to debug this last part.
Any suggestions?
Re: Exiting a Do-While loop
Create the compatible bitmap and the compatible DC in the WM_PAINT handler, not WM_CREATE. Don't forget to delete them at the end of the handler (after the hdcBuff has been blitted to the display's DC).
Mike
Re: Exiting a Do-While loop
Thanks, but still not working.
This is what I did:
Code:
LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
hdcBuff=CreateCompatibleDC(hdcChild);
bmpBuff=CreateCompatibleBitmap(hdcChild, rc.right, rc.bottom);
bmpMain = (HBITMAP)SelectObject(hdcBuff, bmpBuff);
hdcChild = BeginPaint(hWnd, &ps);
UpdateFrame();
EndPaint(hWnd, &ps);
DeleteObject(bmpBuff);
DeleteDC(hdcBuff);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Re: Exiting a Do-While loop
Try
Code:
LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
hdcChild = BeginPaint(hWnd, &ps);
hdcBuff=CreateCompatibleDC(hdcChild);
bmpBuff=CreateCompatibleBitmap(hdcChild, rc.right, rc.bottom);
bmpMain = (HBITMAP)SelectObject(hdcBuff, bmpBuff);
UpdateFrame();
EndPaint(hWnd, &ps);
DeleteObject(bmpBuff);
DeleteDC(hdcBuff);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Re: Exiting a Do-While loop
IT WORKS!! :D (Thank you!)
Trouble is the double-buffer method flickers just as much as the conventional method.
???
edit:
I'm sure the BitBlting is working properly because I changed some of the size parameters,
and the display in the "PictureBox" was only part of the actual size.
Re: Exiting a Do-While loop
Quote:
Originally Posted by mmscg
IT WORKS!! :D (Thank you!)
Glad to hear it!
Quote:
Trouble is the double-buffer method flickers just as much as the conventional method.
Re-read the code at your other thread, particularly at http://www.codeguru.com/forum/showth...4709&p=1048092 . You should notice that to avoid flicker with this double-buffer technique, we need to take over background erasure:
Code:
// erase the background (note: Child window has a NULL background
// brush deliberately, so WM_ERASEBKGRND does nothing; we do this or
// we will still get flicker even if we double-buffer)
HBRUSH br = CreateSolidBrush( g_bgColor );
FillRect( DrawToDC, &rcPlus1, br );
DeleteObject( br );
Mike
Re: Exiting a Do-While loop
ALL graphics are working as supposed to!! :D Thanks again!
Like your sample on double-buffering, this one also makes it very apparent, the
difference between the two methods of displaying graphics.
Actually the principle of double-bufering is quite simple...
but implementing it in win32 C++ is very difficult (for me anyway).
Just one more thing left to do in this app...
interact properly with values entered in an edit control so the user can change one variable if he(she) wishes.
Re: Exiting a Do-While loop
In re-reading your code in the other thread, you placed:
Code:
if ( g_bDoubleBuffer )
{
memDC = CreateCompatibleDC( hdc );
hBitmap = CreateCompatibleBitmap( hdc, rc.right, rc.bottom ); // size of the child window
SelectObject( memDC, hBitmap );
DrawToDC = memDC;
}
else
.
.
.
in the DrawBezier function.
This is what I was initially trying to do in this app (place the CreateCompatibleDC etc in the UpdateFrame function),
but it didn't work.
Should/could this code block also work in the UpdateFrame function?
Did I make another error that prevented it from working there?
Not wanting to waste too much of your time, I am only trying to better understand the logistics of this.
Re: Exiting a Do-While loop
I think (but I'm not positive) that your original attempts to put the memory DC in the UpdateFrame function failed because, at that time, you were defining twenty different mem DC's and drawing a single graphic into each one separately, rather than defining a single mem DC and drawing all graphic objects into the same (common) one, like you're correctly doing now.
Try putting the mem DC into UpdateFrame now, and see if it works, now that you understand the proper way of doing so.
Mike
Re: Exiting a Do-While loop
It works now when I put it UpdateFrame.
I'm glad because I was trying to come up with some sort of reasoning as to why it had to be put it in one place for one type of app, and in another place for another type of app... and couldn't come up with one.
Re: Exiting a Do-While loop
This should be simple, but I am stuck.
I have 90% of my edit control code working, but I am stuck on one detail.
If a user enters a value in one edit control a calculation is made and the result is put in the second edit control (two statics get updated also).
Pretty simple except I end up in an infinite loop (because each edit updates the other).
I thought I had this solved with EM_SETMODIFY, but it seems I can only use it in one of the edits.
If you run the code you will see that if a value is entered in the top edit, the bottom edit is properly automatically updated (along with the two statics).
If a value is entered in the bottom edit the two statics are properly updated, but not the top edit.
It's probably something simple, but I can't figure it out.
Anyone see the problem in the following code?
Code:
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#define RADIO3 400
#define RADIO4 401
#define EDIT_ID1 501
#define EDIT_ID2 502
const char g_szMainWindowClassName[] = "myMainWindowClass";
HINSTANCE hInst;
HWND hMain;
HWND hEdit1;
HWND hEdit2;
HWND hFPS;
HWND hFms;
char cBuf[128];
long FPS;
long msPerFrame;
long StartTime;
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcxM; // for Main Window Class
MSG Msg;
hInst = hInstance; // Store instance handle in our global variable
// Register the Main Window Class
wcxM.cbSize = sizeof(WNDCLASSEX);
wcxM.style = 0;
wcxM.lpfnWndProc = MainWndProc;
wcxM.cbClsExtra = 0;
wcxM.cbWndExtra = 0;
wcxM.hInstance = hInstance;
wcxM.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcxM.hCursor = LoadCursor(NULL, IDC_ARROW);
wcxM.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE+1;
wcxM.lpszMenuName = NULL;
wcxM.lpszClassName = g_szMainWindowClassName;
wcxM.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wcxM))
{
MessageBox(NULL, "Main Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Create the Main Window
hMain = CreateWindowEx(
NULL,
g_szMainWindowClassName,
"Graphics Test",
WS_OVERLAPPEDWINDOW, // | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 630, 340,
NULL, NULL, hInstance, NULL);
if(hMain == NULL)
{
MessageBox(NULL, "Main Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Display the Main Window
ShowWindow(hMain, nCmdShow);
UpdateWindow(hMain);
// Create message loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return static_cast<int>(Msg.wParam);
}
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hGroup2, hRad2_1, hRad2_2 ;
switch (message)
{
case WM_CREATE:
//create text
CreateWindow("static","requested FPS",WS_CHILD|WS_VISIBLE,
320,185,170,20,hWnd,NULL,hInst,NULL);
CreateWindow("static","requested frame time ms",WS_CHILD|WS_VISIBLE,
320,200,170,20,hWnd,NULL,hInst,NULL);
hFPS=CreateWindow("static","static",WS_CHILD|WS_VISIBLE,
500,185,70,20,hWnd,NULL,hInst,NULL);
hFms=CreateWindow("static","static",WS_CHILD|WS_VISIBLE,
500,200,70,20,hWnd,NULL,hInst,NULL);
// create edits
hEdit1 = CreateWindow ("EDIT", "",
WS_CHILD | WS_VSCROLL | WS_VISIBLE |
ES_AUTOVSCROLL | WS_BORDER | ES_NUMBER,
500, 120, 70, 15, hWnd, (HMENU)EDIT_ID1, hInst, NULL) ;
hEdit2 = CreateWindow ("EDIT", "",
WS_CHILD | WS_VSCROLL | WS_VISIBLE |
ES_AUTOVSCROLL | WS_BORDER | ES_NUMBER,
500, 140, 70, 15, hWnd, (HMENU)EDIT_ID2, hInst, NULL) ;
// create group box and radio and radio buttons
hGroup2 = CreateWindow ("BUTTON", "Speed Select",
WS_CHILD | BS_GROUPBOX,
320, 100, 289, 73,
hWnd, NULL, hInst, NULL) ;
hRad2_1 = CreateWindow ("BUTTON", "FPS",
WS_CHILD | BS_RADIOBUTTON,
335, 120, 120, 20,
hWnd, (HMENU)RADIO3, hInst, NULL) ;
hRad2_2 = CreateWindow ("BUTTON", "ms per frame",
WS_CHILD | BS_RADIOBUTTON,
335, 140, 120, 20,
hWnd, (HMENU)RADIO4, hInst, NULL) ;
// display Group2 and radios
ShowWindow (hGroup2, SW_SHOWNORMAL) ;
ShowWindow (hRad2_1, SW_SHOWNORMAL) ;
ShowWindow (hRad2_2, SW_SHOWNORMAL) ;
// start with 1st radio buttons checked
SendMessage (hRad2_1, BM_SETCHECK, TRUE, 0) ;
//temporary only until I figure out edit control
SetWindowText(hEdit1,(LPSTR)"40");
SetWindowText(hEdit2,(LPSTR)"25");
//disable btm edit
EnableWindow (hEdit2, FALSE) ;
break;
case WM_COMMAND:
if(HIWORD (wParam)== EN_CHANGE && LOWORD(wParam) == EDIT_ID1)
{
//MessageBox (hWnd, "Edit1 changed", "Test!", MB_OK) ;
GetWindowText(hEdit1,cBuf,256);
FPS = atoi( cBuf );
msPerFrame = 1000 / FPS;
SetWindowText(hFPS,itoa(FPS,cBuf,10));
SetWindowText(hFms,itoa(msPerFrame,cBuf,10));
//if (SendMessage(hEdit2,EM_SETMODIFY, 0, 0) == FALSE)
//{
SetWindowText(hEdit2, itoa(msPerFrame,cBuf,10));
SendMessage(hEdit2,EM_SETMODIFY, FALSE, 0) ;
//}
}
if(HIWORD (wParam)== EN_CHANGE && LOWORD(wParam) == EDIT_ID2)
{
//MessageBox (hWnd, "Edit2 changed", "Test!", MB_OK) ;
GetWindowText(hEdit2,cBuf,256);
msPerFrame = atoi( cBuf );
FPS = 1000 / msPerFrame;
SetWindowText(hFPS,itoa(FPS,cBuf,10));
SetWindowText(hFms,itoa(msPerFrame,cBuf,10));
if (SendMessage(hEdit1,EM_SETMODIFY, 0, 0) == FALSE)
{
SetWindowText(hEdit1, itoa(FPS,cBuf,10));
SendMessage(hEdit1,EM_SETMODIFY, FALSE, 0) ;
}
}
switch(wParam)
{
case RADIO3: // top radio button of group 2 clicked
SendMessage (hRad2_1, BM_SETCHECK, TRUE, 0) ;
SendMessage (hRad2_2, BM_SETCHECK, FALSE, 0) ;
EnableWindow (hEdit2, FALSE) ;
EnableWindow (hEdit1, TRUE) ;
break ;
case RADIO4: // btm radio button of group 2 clicked
SendMessage (hRad2_1, BM_SETCHECK, FALSE, 0) ;
SendMessage (hRad2_2, BM_SETCHECK, TRUE, 0) ;
EnableWindow (hEdit1, FALSE) ;
EnableWindow (hEdit2, TRUE) ;
break ;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
1 Attachment(s)
Re: Exiting a Do-While loop
EM_SETMODIFY had nothing to do with my problem
(which is good because I can't figure out the proper usage of this).
Anyways, I solved the problem in a much simpler way.
My project is now complete and works OK. :D
The only thing I don't like is my actual vs requested times is not very close,
and I suspect it has something to do with the resolution of GetTickCount()
Also the display of the actual times updates so quickly, it is a blur and hard to read
(my VB version doesn't run this quickly).
One warning during build that I don't know how to correct:
warning C4800: 'LRESULT' : forcing value to bool 'true' or 'false' (performance warning)
Here is the final code:
Comments regarding the proper C++ way to do things (if I've done things very wrong) would be welcome.