Re: Exiting a Do-While loop
Quote:
Originally Posted by mmscg
OK, I don't think the problem is a
graphics one, but rather not understanding how to return an array thru a function
I have a user-defined type
"Box" and I declare an array
GraphicObject[20] of type Box
In my function
UpdateFrame, I call the function
MoveGraphicObject
inside a for-loop that should fill all the parameters of a 20 element array.
ie
Code:
for (i=0; i<=19; i++)
{
MoveGraphicObject(GraphicObject[i][i]);
}
Since GraphicObject is declared a global variable these values should be available anywhere in the program
In my MessageBox "debugger"
Code:
wsprintf (cBuf, "%d", GraphicObject[i].x1 );
MessageBox(NULL, cBuf, "Test", MB_OK);
always returns
zero (ditto GraphicObject[i].y1, GraphicObject[i].x2,GraphicObject
.y2, etc.)
yet I know MoveGraphicObject is calculating the values correctly because I do a similar test inside that function, and values other than zero are displayed.
Can anyone see, what I am doing incorrectly in this regard?
In C++, parameters for a function are passed by value (unless you specify otherwise).
What that means is that a copy of your "Box" object is created, and the value of the copy is passed into the function and worked on by the function. The original "Box" object is untouched by whatever occurs inside the function.
The way around this is to pass a reference to the "Box" object into the function. You do this by declaring the signature of the function as follows:
Code:
void MoveGraphicObject(Box& Obj) // notice the "&"
This overrides the default C++ behavior for functions, and causes a reference to the "Box" object to be passed, instead of its value. There are no changes needed to call the function:
Code:
MoveGraphicObject(GraphicObject[i]); // will work just fine
It's also possible to pass the "Box" object in to the function as a pointer to the object, but in this situation, the reference is probably better.
Mike
Re: Exiting a Do-While loop
Thanks!
In VB it is the opposite (by reference) and I just assumed it was the same in C++.
That should help me continue with the debugging as now I know what to look for.
BTW, I've got some graphics happening in my "PictureBox" now. :D
Lots of bugs in this C++ version however.
Re: Exiting a Do-While loop
hmm.
I get the following error:
LNK1120: 1 unresolved externals
This is what I did:
//function prototype
void MoveGraphicObject(Box);
//function
void MoveGraphicObject(Box& Obj)
{
<code>
}
//function call
MoveGraphicObject(GraphicObject[i]);
Re: Exiting a Do-While loop
You've gotta change the function prototype also...
//function prototype
void MoveGraphicObject(Box &Obj);
Hope this helps,
- Nigel
Re: Exiting a Do-While loop
I really want to commend you for trying to learn this Windows API stuff; it's hard and you should be encouraged to continue.
But I also think you need to re-think your design. Once again (as in your "Mouse Co-ordinates in Static Control" post http://www.codeguru.com/forum/showthread.php?t=314709 ) you refuse to do your drawing in the WM_PAINT handler. That's where it belongs, and unless you do it there, your app will exhibit pathological behavior when it needs to redraw itself in response to outside events (like being covered and then uncovered by another window).
Parts of your design seem very "procedural", as contrasted to simple responses to outside events (as reported to you by messages); are you perhaps a former Fortran programmer? Your code very linear and you obviously want to take responsibility for all aspects of the program's functionality, even those aspects which are rightly the responsibility of the Windows OS.
For example, why don't you want to use timers? (per your post yesterday: "I didn't want to use a timer") A timer is the correct approach for your app to be notified periodically of the elapse of a selected time (within some somewhat coarse resolution (around 10 milliseconds) and jitter). Instead, you seem ****-bent on capturing complete control of the CPU when the "Run" button is clicked, and not releasing it until "Quit". You even want to take control away from your own application's message pump and process messages within the button click handler.
That's not the way to think about applications in Windows. Applications should basically be lazy: do nothing unless somebody tells us that an event we're interested in has occurred. That's why we "switch" on only a certain few messages and call "DefWindowProc" for the vast majority of them.
And even for the messages we're interested in, we do the least possible work, commensurate with the nature of the message. For example, in your program, there is absolutely no logical connection between the position-update of your "Box" objects and the drawing of them. There are plenty of situations where you need to draw your objects even though there has been no update in their positions. (Think minimize-maximize of the window; there's no update of position, but sure as heck there's a need to re-draw.) Conversely, although it's true true that you need to re-draw after updating position, but maybe you don't need (or you can't get) re-drawing after each and every single postion update. Remember, this is a multi-threaded, multi-application environment, where there are many programs competing with yours for time on the CPU. So, your application needs to be flexible and realize that these other programs might consume enough CPU cycles that it's not possible to re-draw after every position update. That's the beauty of the InvalidateRect function (which should be called at the end of your postion update): it invalidates your client rectangle, but Windows will not post a WM_PAINT message to your app until it's ready to, even if that's not until after several position updates, at which time you wil get only a single WM_PAINT message which will trigger you to re-paint.
Rethink your design. Do the smallest possible chunk of work that's appropriate for the message that you're processing. Be lazy and do no more than you're told to by the OS.
Mike
Re: Exiting a Do-While loop
NigelQ:
Yes that helps... it works now! :D (well that part anyway)
MikeAThon:
Thanks for the encouragement!
My latest code now has the drawing in the WM_PAINT handler.
I don't know what I was doing wrong initially, but when the program ran it was a mess. When I tried to drag the form only half would move... my screen would go totally gray, and my bottom "start" bar (or whatever it is called) would move to the top of the screen...
a black Dos style screen would appear in one corner, and I could see continuous
printing like "Unable to connect to server... try again... server contacted etc
I must have some spyware or something running in the background and my program exposed it.
All is OK now and I don't know what I did.
Fortran was the language I learned in university... that was a few years ago though.
Maybe my VB version of this app is a poor design also, I don't know... it seems to function OK.
Since I have gone this far with the current architecture, I am going to continue.
Perhaps when (if) I get this working, you could spend a few minutes and re-organize the code (or instruct me to) in the proper C++ way.
I had the same problem when first learning VB; thinking in terms of "events" rather than top-to-bottom programming.
Since C++ is much lower level, I see I have to learn to think differently once again.
Re: Exiting a Do-While loop
I'm pleased you got it working now, but I've got to agree with Mike, you should really look at what you are trying to achieve.
It sounds like there must be an easier way to get to where you're going...
Regards,
- Nigel
Re: Exiting a Do-While loop
Still having a bit of trouble with the user-defined Box type GraphicObject array
The way the following code is supposed to operate is:
any clicking of the Display button should display TRUE (1) (ie GraphicObject[0].newB = TRUE ) until the Move button is clicked, at which point any subsequent clicking of the Display button should always display FALSE (0) (ie GraphicObject[0].newB = FALSE )
Actually, in pruning down the code to post here, I find it to behave properly except if I uncomment the wsprintf/MessageBox pairs that bracket the line Obj.newB = FALSE; in the MoveGraphicObject function
then
clicking the Display button always displays 1
My main project behaves this way (GraphicObject[0].newB always equals TRUE).
This is wrong and causing an incorrect display of my graphics.
Why does adding MessageBoxes cause GraphicObject[0].newB to be assigned incorrect values?
Can't really continue, until I solve this problem.
Code:
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#define IDB_BTN100 100
#define IDB_BTN200 200
const char g_szMainWindowClassName[] = "myMainWindowClass";
HINSTANCE hInst;
HWND hMain;
HWND hBtn100;
HWND hBtn200;
char cBuf[128];
typedef struct
{
bool newB;
long x1;
long y1;
long x2;
long y2;
long speed;
long interval;
int direction;
COLORREF color;
}Box;
Box GraphicObject[20];
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
void MoveGraphicObject(Box &Obj); //You've gotta change the function prototype also...
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, 390,
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)
{
switch (message)
{
case WM_ACTIVATEAPP:
int i;
for (i = 0; i<=19; i++)
{
GraphicObject[i].newB = TRUE;
}
break;
case WM_CREATE:
//create the push buttons
hBtn100 = CreateWindow("button", "Move", WS_CHILD|WS_VISIBLE,
10, 10, 137, 25, hWnd, (HMENU)100, hInst, NULL);
hBtn200 = CreateWindow("button", "Display", WS_CHILD|WS_VISIBLE,
10, 40, 137, 25, hWnd, (HMENU)200, hInst, NULL);
break;
case WM_COMMAND:
switch(wParam)
{
case IDB_BTN100: // Run button
MoveGraphicObject(GraphicObject[0]); // will work just fine
return 0;
case IDB_BTN200: // Quit button
wsprintf (cBuf, "GraphicObject[0].newB = %d", GraphicObject[0].newB) ;
MessageBox (hWnd, cBuf, "Current Button Status", MB_OK) ;
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void MoveGraphicObject(Box& Obj) // notice the "&"
{
if ( Obj.newB == TRUE )
{
//wsprintf (cBuf, "MoveGraphicObject [before] %d", (int)(Obj.newB) );
//MessageBox(NULL, cBuf, "Test", MB_OK);
Obj.newB = FALSE;
//wsprintf (cBuf, "MoveGraphicObject [after] %d", (int)(Obj.newB) );
//MessageBox(NULL, cBuf, "Test", MB_OK);
}
else
{
//
}
}
Re: Exiting a Do-While loop
I'm not sure why putting the MessageBox entries there is causing you problems. It could be that you are not using the current window as the parent for these messageboxes:
MessageBox(hMain, cBuf, "Test", MB_OK);
...would be better.
But I wouldn't even put MessageBox calls in this routine at all. If anywhere, I'd put them in your MainWndProc.
I'm not sure what other problems you are describing there (it's difficult to understand), but your MoveGraphicObject routine will always return with the Obj.newB set to FALSE (note that you should be using false for bool variables, not the uppercase FALSE).
If this function returning newB as false (or FALSE) is incorrect, then there is a problem with the routine. Let me know what this function is meant to be doing when the newB is both true and also when false upon entry.
In addition, your "Display" (or is it Quit) handler does not seem to be doing anything other than display the value of newB - is this correct?
Hope this helps,
- Nigel
Re: Exiting a Do-While loop
Quote:
MessageBox(hMain, cBuf, "Test", MB_OK);
I'll try that.
Quote:
I'm not sure what other problems you are describing there (it's difficult to understand), but your MoveGraphicObject routine will always return with the Obj.newB set to FALSE (note that you should be using false for bool variables, not the uppercase FALSE).
No other problems... I will change TRUE/FALSE to true/false and see if that makes a difference.
Quote:
If this function returning newB as false (or FALSE) is incorrect, then there is a problem with the routine. Let me know what this function is meant to be doing when the newB is both true and also when false upon entry.
This is what I want, but my posted code doesn't do that (with the messageboxes)
Quote:
In addition, your "Display" (or is it Quit) handler does not seem to be doing anything other than display the value of newB - is this correct?
Should be Display in this context.
The purpose of the program is just to debug the value of newB, so I didn't have this handler do nothing more than display the value of newB so I can see if it was in fact changed to false.
Re: Exiting a Do-While loop
Quote:
Originally Posted by from MSDN
WM_ACTIVATEAPP
The WM_ACTIVATEAPP message is sent when a window belonging to a different application than the active window is about to be activated. The message is sent to the application whose window is being activated and to the application whose window is being deactivated.
So, every time your app is activated, you re-set GraphicObject[0].newB back to TRUE (in fact, you re-set all of the GraphicObjects back to TRUE). And WM_ACTIVATE happens alot (put a breakpoint in it) and most certainly happens after you close a MessageBox whose parent handle is NULL (i.e., the two MessageBox's that you have commented out).
Put your initialization of GraphicObject into WinMain.
Mike
Re: Exiting a Do-While loop
OK, Ive incorporated corrections from previous posts, and fixed all my code requiring C++'s rand() functions
(I had totally gotten this wrong).
I now have GraphicObjects moving around the screen, but they don't look or behave anything like their VB counterparts.
Perhaps I am still not working with the rand() function correctly.
I created two routines to test.
Code:
case IDB_BTN100:
//seed the random number generator
srand((unsigned)time(0));
int testRGBcomponent;
testRGBcomponent = (int)(256*rand()/(RAND_MAX + 1.0));
wsprintf (cBuf, "testRGBcomponent = %d", testRGBcomponent) ;
MessageBox (hWnd, cBuf, "Debug MessageBox", MB_OK) ;
return 0;
case IDB_BTN299:
//seed the random number generator
srand((unsigned)time(0));
COLORREF testColor;
testColor = RGB((int)(256*rand()/(RAND_MAX + 1.0)),
(int)(256*rand()/(RAND_MAX + 1.0)),
(int)(256*rand()/(RAND_MAX + 1.0)));
wsprintf (cBuf, "testColor = %d", testColor) ;
MessageBox (hWnd, cBuf, "Debug MessageBox", MB_OK) ;
return 0;
The code in BTN299 produces a different number each time the button is clicked (so I assumed it was working correctly).
The code in BTN100 is supposed to generate a random number between 0 and 255. What actually happens is it produces the same number at each button click, and then increments by one after several seconds, and again this number is repeated for several seconds and so on.
This doesn't seem to random to me.
All GraphicObject's parameters are filled in using rand(), so I will be calculating everything wrong, which explains the wrong behaviour.
I've checked and re-checked a number of C++ random number tutorials, and I'm sure I'm doing this correctly.
Can anyone see what I am doing wrong now?
Re: Exiting a Do-While loop
Nevermind.
I find that if I comment out srand((unsigned)time(0)); (ie don't seed the random number generator at each button click), it works as I expect.
This makes no sense at all to me because even if it is re-seeded every time, the seed is always changing (because it is based on time which is always changing).
:confused:
Re: Exiting a Do-While loop
I think you should run your do-while loop in a separate thread using
AfxBeginThread method.
Using this your problem will definitely get solved.
Re: Exiting a Do-While loop
Quote:
Originally Posted by mmscg
...This makes no sense at all to me because even if it is re-seeded every time, the seed is always changing (because it is based on time which is always changing).....
Quote:
Originally Posted by MSDN
The time function returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time, according to the system clock. ...
So, the time() function changes, at most, only once per second.
Quote:
Originally Posted by MSDN
The srand function sets the starting point for generating a series of pseudorandom integers.
So, you're re-initializing the rand() function with exactly the same value for at least one full second. Although this doesn't fully explain why you get the same number for up to a few seconds, it sure goes a long way in explaining the behavior you're seeing (or, more accurately, the behavior you were seeing).
Call srand() only once per program. The best place is in some sort of initialization function, like in the beginning of WinMain. Then you'll get the rand() behavior you want.
@manish_gcet: AfxBeginThread is an MFC function that's not appropriate here in a pure Win32 environment. Anyway, so far it doesn't look like threads are needed.
Mike