In order to exit the loop I have set up a boolean variable that, when set, is used to exit the loop.
Problem is, the loop does not yield to other processes (ie being able to press the "Quit" button, which sets the boolean variable enabling a way to exit the loop).
VB has a DoEvents function which allows other processes to be carried out in a loop such as this.
Since C++ does not have DoEvents I used the following in it's place.
The most straight-forward solution is to run your loop in a separate thread. Otherwise, as you already found out, your program will not "yield" any processor time to handling of other tasks in your program, like clicking on the "Quit" button.
Threads, however, intorduce complications into your program, most notably the need to synchronize access to shared data and to synchronize inter-thread event communications. One alternative to a separate thread is a so-called "gaming loop" for your message loop. For example, see http://www.codeproject.com/wtl/wtlgameloop.asp or http://www.mvps.org/directx/articles/writing_the_game_loop.htm
This transforms your message loop into a sort of poor-man's multi-threaded app, except that there's only one thread. To work successfully, however, you will need to ensure that your "continual loop" is actually broken up into iterations, and that only one iteration is run before yielding to the PeekMessage part of the message loop.
Incidentally, I won't tell you why your app is crashing (even though it's fairly evident) because your design is truly "not recommended". See, for example, the comments on PeekMessage in "The n Habits of Highly Defective Windows Applications" at http://www.flounder.com/badprogram.htm#Using%20PeekMessage%20anywhere
Mike
amarcode
November 11th, 2004, 09:34 AM
My project requires a continual loop.
The following code compiles and runs, but crashes with the error
The instruction at "0x00000064" refrenced memort at "0x00000064". The memory could not be "read".
when the Quit button is depressed.
Can anyone spot the problem?
The PeekMessage, DispatchMessage and TranslateMessage functions use MSG type not UINT as parameters. Try this :
do
{
MSG msg;
while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
{
DispatchMessage (&msg);
TranslateMessage (&msg);
}
}
while (bQuit == FALSE);
mmscg
November 11th, 2004, 06:28 PM
amarcode:
Works great! Thank you! :D
MikeAThon:
I checked out PeekMessage on the ....badprogram... link :D
I could not understand anything the author was trying to say (except I am breaking every rule in the book)
because his code snippets all use MFC, which I know nothing about.
I also looked at the "game loop" links you provided, and they seem identical to what I am trying to do except
they wrap this "continual loop" around the WinMain message pump.
In my situation I only wanted to activate this loop at a press of a button (and exit it in the same way).
If I still am not understanding what you are trying to say, please respond.
And thanks also for again taking time to help!
NigelQ
November 11th, 2004, 07:55 PM
You may also want to check your CPU utilization when running this loop. You might want to put a Sleep in there to yield to other running processes (such as the operating system)...
do
{
MSG msg;
while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
{
DispatchMessage (&msg);
TranslateMessage (&msg);
Sleep(0);
}
}
while (bQuit == FALSE);
Hope this helps,
- Nigel
mmscg
November 11th, 2004, 09:08 PM
Yes I have Sleep(0); in my loop.
I really wasn't sure where to put it so I ended up putting it here:
do
{
MSG msg;
while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
{
DispatchMessage (&msg);
TranslateMessage (&msg);
}
Sleep(0);
}
while (bQuit == FALSE);
Do you think it makes a difference as to where in the loop?
NigelQ
November 11th, 2004, 09:19 PM
Ah, so you do... :p
If you have a lot of messages (depending on what you're doing), the inner loop could snag 100% of the CPU time while processing messages.
Putting the Sleep inside the inner while would avoid this, but given a regular set of messages, as you have it will likely be fine.
( I would have put it in the inner loop, but that's just me )
Regards,
- Nigel
mmscg
November 11th, 2004, 09:56 PM
So to be safe, I shall move it then.
Thanks! :)
MikeAThon
November 11th, 2004, 10:02 PM
Sleep(0) should not be used here. It causes the current thread to yield the remainder of its time-slice to any other thread in the system with a higher current priority. It therefore will do two things here which seem wrong: it will rob your own program of valuable CPU time that it probably needs to complete its own tasks, and it will mask problems caused by incorrect program architecture that improperly over-utilizes the CPU.
The thread scheduler in Windows is smarter than your program about when to stop your program (at the natural end of its timeslice) and to let others run in their timeslice. Let Windows do its job.
@mmscg: To use the "game loop", your "run" button should merely set a global boolean to TRUE, and your "quit" button should set it to false. Then, in the main message loop, test the value of the global and run your "contiual loop" if it's TRUE and don't if it's FALSE.
Mike
NigelQ
November 11th, 2004, 10:14 PM
Mike,
I disagree.
Removing the sleep prevents the windows task scheduler from doing its job, by forcing this thread to consume almost all of the spare CPU cycles in the machine.
By giving up the remainder of the timeslice, you are permitting window to perform other essential scheduling.
Otherwise in a tight loop, like this...
while(1)
;
This thread will use 100% of the CPU, regardless of its thread priority and other applications will not have their required share of the slices.
In fact I would go as far as saying that without the sleep in his loop, the thread will consume 100% of his CPU, while it is sitting doing (next to) nothing.
Hope this helps,
- Nigel
mmscg
November 12th, 2004, 07:27 AM
I found this in a Microsoft article:
DoEvents is a Visual Basic function that yields execution so the operating system can process other events. This function cleans out the message loop and executes any other pending business in the Visual Basic runtime. Upon completing the pending business execution, the function calls the Sleep function with zero (0) as the argument so that the remaining time slice can be used to check the queue.
The Sleep 32-bit API function is a subset of the DoEvents function. The Visual Basic program calling the function and the Visual Basic runtime executable and interactions with Windows are immediately put to sleep by this function. The programs remain inactive for the time in milliseconds specified in the Sleep argument.
The Sleep function allows you to specify the amount of time your applications are inactive. The DoEvents function returns control to the Visual Basic program after the operating system has finished processing the events in its queue and all keys in the SendKeys queue have been sent.
Does this say where they put the Sleep(0) call?
MikeAThon
November 12th, 2004, 09:44 AM
Don't try to use VB concepts in Win32 programming, at least not without understanding the full VB framework. For example, if the text you quoted is referring to the Win32 Slepp() API function, then it makes no sense to say that "the Sleep function [is called] with zero (0) as the argument so that the remaining time slice can be used to check the queue." The Win32 Sleep function immediately yields the time-slice, so that there's nothing left with which to "check the queue". Tis makes me think that the quoted text is referring to some VB wrapper to the Sleep() function, that does some extra work with the VB framework before it calls the actual Win32 Sleep() function.
You need to describe what you want to do in your "continual loop". But again, I strongly recommend against Sleep(0), and you probably will not need it.
@Nigel: I know you disagree, but Sleep(0) is usually a sign of architecture that needs improvement. For example, the programmer does not know why the app is eating 100% CPU time and feels it should not be, but can't figure out any other way to stop it, so he sticks a Sleep(0) (or worse, a Sleep(100)) in it. This would be a bad reason to use Sleep().
One common use of Sleep(0) is in multi-threaded situations, where you need to play some sort of inter-thread "catch up" and you have determined that one thread has done all it can for now, and must wait for another thread to complete processing that the first thread needs. In such a situation, the first thread's continued use of its time-slice is wasteful, since we already know that it can't do anything further; it should therefore yield its time-slice, and Sleep(0) might make sense here. (WaitForSingleObject might make more sense, but each situation should be evaluated on its own.)
Mike
PS: There's almost never a justification for using Sleep(100), or anything above Sleep(0), for the reason that the "100" is usually an arbitrary number that the programmer found experimentally to "get it to work", without fully understanding why it didn't work in the first place. This is guaranteed to fail on someone else's system, at some time in the future.
mmscg
November 14th, 2004, 10:27 AM
You need to describe what you want to do in your "continual loop". But again, I strongly recommend against Sleep(0), and you probably will not need it.
I thought I would be able to complete this on my own... I was wrong.
I was continuing with the "double-buffering" for graphics. I could not get the previous one working, so I continued to read up on the subject, thought I understood it, implemented it in VB (works GREAT), and now trying to build it in C++ Win32.
The "continual loop" is there to generate random graphics in the "PictureBox", so that I could watch the effect with double-buffering ON and OFF (I didn't want to use a timer).
I am posting my code. It builds and runs, but NO graphics appears in my "PictureBox".
I tried calling UpdateFrame in the WM_PAINT handler, and InvalidateRect whereI had called UpdateFrame.
This didn't work, and in fact caused strange screen behaviour.
If anyone is able to help, it would be appreciated, as I am becoming very frustrated, that this graphics part is not really sinking-in for me.
mmscg
November 14th, 2004, 11:04 PM
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
for (i=0; i<=19; i++)
{
MoveGraphicObject(GraphicObject[i]);
}
Since GraphicObject is declared a global variable these values should be available anywhere in the program
always returns zero (ditto GraphicObject[i].y1, GraphicObject[i].x2,GraphicObject[i].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?
always returns zero (ditto GraphicObject[i].y1, GraphicObject[i].x2,GraphicObject[i].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:
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:
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
mmscg
November 15th, 2004, 11:02 PM
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
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
mmscg
November 15th, 2004, 11:46 PM
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.
NigelQ
November 15th, 2004, 11:53 PM
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
mmscg
November 16th, 2004, 08:36 PM
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.
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?
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.
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)
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.
MikeAThon
November 16th, 2004, 11:10 PM
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
mmscg
November 17th, 2004, 05:38 PM
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.
case IDB_BTN100:
//seed the random number generator
srand((unsigned)time(0));
int testRGBcomponent;
testRGBcomponent = (int)(256*rand()/(RAND_MAX + 1.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?
mmscg
November 17th, 2004, 11:35 PM
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:
manish_gcet
November 18th, 2004, 12:26 AM
I think you should run your do-while loop in a separate thread using
AfxBeginThread method.
Using this your problem will definitely get solved.
MikeAThon
November 18th, 2004, 12:46 AM
...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).....
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.
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
mmscg
November 18th, 2004, 11:28 PM
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?
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;
//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;
}
}
mmscg
November 21st, 2004, 09:46 PM
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, ...
//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:
// 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?
MikeAThon
November 21st, 2004, 10:03 PM
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).
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.
MikeAThon
November 22nd, 2004, 09:37 PM
IT WORKS!! :D (Thank you!)Glad to hear it!
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/showthread.php?t=314709&p=1048092 . You should notice that to avoid flicker with this double-buffer technique, we need to take over background erasure:
// 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)
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.
mmscg
November 23rd, 2004, 12:00 PM
In re-reading your code in the other thread, you placed:
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.
MikeAThon
November 23rd, 2004, 11:52 PM
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
mmscg
November 24th, 2004, 07:58 PM
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.
mmscg
November 24th, 2004, 08:42 PM
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.
}
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;
}
mmscg
November 30th, 2004, 08:14 PM
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.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.