Prev: Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application
Next: Warning: Cannot load CRuntimeMap from archive. Class not defined.
From: Joseph M. Newcomer on 18 Nov 2006 01:04 See below... On Fri, 17 Nov 2006 19:54:32 -0500, "Scott McPhillips [MVP]" <org-dot-mvps-at-scottmcp> wrote: >MarcoMB wrote: >> i looked at Scribble example in my MSDN samples section but unfortunatly i >> didn't found something to solve my problem, since scribble regards only line >> object that haven't to be continously deleted and redrawed on DC like my >> geometric and user positioning object...i rather think maybe i wold have to >> implement a bufer DC...do you? > >The lesson that you should have learned from the Scribble tutorial is >that you have to draw the objects in the OnDraw function. If you don't, >they disappear. **** This is elementary graphics programming; and indeed, that's why I told you that you have to do the Scribble tutorial. **** > >The WM_MOUSEMOVE handler should just change variables and call >Invalidate. It should not draw. Invalidate causes OnDraw to execute, and >it uses the changed variables to draw. **** You can draw directly using XOR-style drawing (which is another point the Scribble tutorial illustrates). There are tradeoffs between doing direct drawing in the WM_MOUSEMOVE handler and using the OnDraw handler which the tutorial also discusses, but ultimately you MUST create the permanent information used by the OnDraw handler and call Invalidate to force the actual object to be drawn. WHen you have multiple layers of drawing, the OnDraw is best, and you reduce flicker by invalidating the smallest possible area for the redrawing. You can reduce it further by clever use of OnEraseBkgnd and if necessary doing a double-buffered mechanism where you draw on a bitmap then BitBlt the bitmap to the view window. However, until you've mastered the basics of how drawing works, worrying about optimizations is low priority. **** > >Another example program that may help you is the DrawCLI MFC sample >program. It is an example of a drawing editor program. Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: MarcoMB on 18 Nov 2006 16:13 thanks for all support... i created different class, one per object(class for circles, class for rectangle, etc) and i've implemented CObArray containing objects drawed and so created.In every objects class there's the related Draw function that substitute the onDraw, called only when Invalidate to make cycles in the arrays and so redraw the objects.My problem was mantaining objects on screen when positioning them, becouse invalidating constinously their little area(to eliminate flicker)i lost the object when there wasn't mouse moving.I resolved my problem introducing an event function OnTimer so that i can redrawing continously object even if WM_MOUSEMOVE isn't called.I don't know if it's the right way, but it's work fine.I thought also to manage the OnIdle thread, but i don't know if it's better.Maybe the best could be creating a buffer DC abd then BitBlt the image, also if i draw DC objects that aren't bitmaps so how can work a buffer DC and BitBlt?
From: Joseph M. Newcomer on 18 Nov 2006 18:42 see below... On Sat, 18 Nov 2006 13:13:02 -0800, MarcoMB <MarcoMB(a)discussions.microsoft.com> wrote: >thanks for all support... i created different class, one per object(class for >circles, class for rectangle, etc) **** You are being very vague here about what you did. I would expect that you have done class Drawing { public: virtual void Draw(...some args...) PURE; .... }; class Circle : public Drawing { public: virtual void Draw(...some args...); }; class Rectangle : public Drawing { public: virtual void Draw(...some args...); }; If you did not do this, why not? **** >and i've implemented CObArray containing >objects drawed and so created. **** Generally, get nervous when you declare a CObArray. They aren't type-safe. As a good basic design principle, take as given "If I'm writing a CObArray, I've made a mistake", and go from there. There might exist, in some weird and wondrous world, a need for a CObArray, but I've never found one. Beginners latch onto this because it seems to be a simple solution, but in fact it is one of the worst possible choices. CArray<Drawing *, Drawing *> objects; The alternative is to create a CList of Drawing objects, which has different tradeoffs but is otherwise an equally valid implementation of a display list. The Z-order is implicit in the array. The bottommost object is at position 0 and the topmost object at position GetSize() - 1. If you want to change the Z-order of an object, you change its position in the array (now you understand how Move Forward and Move Backward work in most drawing programs: they swap the element with the one after it (Move Forward) or the one before it (Move Backward). Move To Top moves the element to the last position, and Move To Bottom moves the element to position 0). **** >In every objects class there's the related Draw >function **** What is a "related function"? I've never heard this term used in C++ programming ***** >that substitute the onDraw, ***** That doesn't make any sense. It would be *called* from OnDraw, but it wouldn't *substitute* for OnDraw. ***** >called only when Invalidate to make >cycles in the arrays and so redraw the objects. **** Other than the strange description, this would be the basic idea. A prety good approximation to what you need to do in OnDraw is shown below. There could be issues of setting mapping modes, origins, and a few other bells and whistles, but the core algorithm is very simple: void CMyClass::OnDraw(CDC * pDC) { for(int i = 0; i < objects.GetSize(); i++) objects[i]->Draw(pDC); // "some args" might just be the pDC, for example... } **** >My problem was mantaining >objects on screen when positioning them, becouse invalidating constinously >their little area(to eliminate flicker)i lost the object when there wasn't >mouse moving. **** This makes no sense. You *can't* "lose" an object because it is still in the display list; all that has changed is its x,y origin position. So if you invalidate its original location (as you come into OnMouseMove) and its target location (as you leave OnMouseMove), it will simply be redrawn. Where's the problem? **** I resolved my problem introducing an event function OnTimer so >that i can redrawing continously object even if WM_MOUSEMOVE isn't called. **** ABSOLUTELY THE WRONG APPROACH! There are so many things wrong with this concept I'm not even sure where to begin! You should only draw when you need to draw, and that means you respond to WM_PAINT messages. This is the OnDraw handler. The rest of the time, you don't draw. Constantly redrawing based on a timer event is wasteful, and frankly, nonsensical. You are trying to solve a problem whose solution is well-understood and well-specified, and you are missing the basic concepts and have failed to understand how Windows grpahics work, and as a consequence you are seeing weird behavior, which you are flailing about attempting to fix, when simply implementing the correct solution (OnDraw) would make go away. You have to keep the information necessary to re-create the entire drawing, from scratch, without warning, at any time. Without this, the kinds of problems you are seeing follow naturally from a misdirected solution. And your attempts to "solve" it are completely off-base. If you are "losing" the object being dragged, it says there is a fundamental failure in your algorithm, and tossing kludges at it isn't going to solve the fundamental problem. Fix the fundamental problem. I have no idea what you are doing wrong, but the proposed solution is, to say the least, nonsensical. You really have to CAREFULLY STUDY the Scribble tutorial; you have missed the fundamental concepts of Windows graphics completely! **** >I don't know if it's the right way, but it's work fine.I thought also to manage >the OnIdle thread, **** There is no such thing as "the OnIdle thread". There is an OnIdle handler which is called in your main GUI thread if there is nothing else to do, but this is equally poor design to use this for your redrawing. PLEASE study how graphics work in Windows; you are simply kludging together hopelessly incorrect solutions otherwise. **** >but i don't know if it's better.Maybe the best could be >creating a buffer DC abd then BitBlt the image, also if i draw DC objects >that aren't bitmaps so how can work a buffer DC and BitBlt? **** Drawing your objects on a bitmap merely renders the circle, rectangle, etc. as bits (which is what is done when you draw them directly to the screen), but the use of the intermediate bitmap reduces flicker because this intermediate bitmap can be transferred to the visible window within one frame time. But until you get the fundamental algorithms right, worrying about optimizations like this is inappropriate. Get the core tecnology right, FIRST. Right now, you are a very long way from that. You have obviously missed all of the key ideas in the Scribble tutorial, because you fixated on trivia such as lines vs. objects. Study the core algorithms first. Then you can see how they generalize to other objects. joe ***** Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: MarcoMB on 18 Nov 2006 19:55 Thanka a lot for your patience with me, i please you to understand i'm trying to learn on myself Visual C++ studying on book etc, and it's not my true job, i make it only for passion.So i tried to handle the static draw of my objects in WM_PAINT message as you said, and it's ok, the solution was under my eyes .... i'm going to studing Scribble carefully following your advice...and i'll consider all your help like gold...unfortunately i based my app on a sample tutorial i found on book that to mantain simple learning based the object on CObArray, but i've read what you say that it's going wrong with those type of generic object, and use instead template class that accept only specified type of data object like CArray.I'll try to modify my simple paint app...thanks a lot again. "Joseph M. Newcomer" wrote: > see below... > On Sat, 18 Nov 2006 13:13:02 -0800, MarcoMB <MarcoMB(a)discussions.microsoft.com> wrote: > > >thanks for all support... i created different class, one per object(class for > >circles, class for rectangle, etc) > **** > You are being very vague here about what you did. I would expect that you have done > > class Drawing { > public: > virtual void Draw(...some args...) PURE; > .... > }; > > class Circle : public Drawing { > public: > virtual void Draw(...some args...); > }; > > class Rectangle : public Drawing { > public: > virtual void Draw(...some args...); > }; > > If you did not do this, why not? > **** > >and i've implemented CObArray containing > >objects drawed and so created. > **** > Generally, get nervous when you declare a CObArray. They aren't type-safe. As a good > basic design principle, take as given "If I'm writing a CObArray, I've made a mistake", > and go from there. There might exist, in some weird and wondrous world, a need for a > CObArray, but I've never found one. Beginners latch onto this because it seems to be a > simple solution, but in fact it is one of the worst possible choices. > > CArray<Drawing *, Drawing *> objects; > > The alternative is to create a CList of Drawing objects, which has different tradeoffs but > is otherwise an equally valid implementation of a display list. > > The Z-order is implicit in the array. The bottommost object is at position 0 and the > topmost object at position GetSize() - 1. If you want to change the Z-order of an object, > you change its position in the array (now you understand how Move Forward and Move > Backward work in most drawing programs: they swap the element with the one after it (Move > Forward) or the one before it (Move Backward). Move To Top moves the element to the last > position, and Move To Bottom moves the element to position 0). > **** > >In every objects class there's the related Draw > >function > **** > What is a "related function"? I've never heard this term used in C++ programming > ***** > >that substitute the onDraw, > ***** > That doesn't make any sense. It would be *called* from OnDraw, but it wouldn't > *substitute* for OnDraw. > ***** > >called only when Invalidate to make > >cycles in the arrays and so redraw the objects. > **** > Other than the strange description, this would be the basic idea. > > A prety good approximation to what you need to do in OnDraw is shown below. There could > be issues of setting mapping modes, origins, and a few other bells and whistles, but the > core algorithm is very simple: > > void CMyClass::OnDraw(CDC * pDC) > { > for(int i = 0; i < objects.GetSize(); i++) > objects[i]->Draw(pDC); // "some args" might just be the pDC, for example... > } > **** > >My problem was mantaining > >objects on screen when positioning them, becouse invalidating constinously > >their little area(to eliminate flicker)i lost the object when there wasn't > >mouse moving. > **** > This makes no sense. You *can't* "lose" an object because it is still in the display > list; all that has changed is its x,y origin position. So if you invalidate its original > location (as you come into OnMouseMove) and its target location (as you leave > OnMouseMove), it will simply be redrawn. Where's the problem? > **** > I resolved my problem introducing an event function OnTimer so > >that i can redrawing continously object even if WM_MOUSEMOVE isn't called. > **** > ABSOLUTELY THE WRONG APPROACH! There are so many things wrong with this concept I'm not > even sure where to begin! You should only draw when you need to draw, and that means you > respond to WM_PAINT messages. This is the OnDraw handler. The rest of the time, you > don't draw. Constantly redrawing based on a timer event is wasteful, and frankly, > nonsensical. You are trying to solve a problem whose solution is well-understood and > well-specified, and you are missing the basic concepts and have failed to understand how > Windows grpahics work, and as a consequence you are seeing weird behavior, which you are > flailing about attempting to fix, when simply implementing the correct solution (OnDraw) > would make go away. You have to keep the information necessary to re-create the entire > drawing, from scratch, without warning, at any time. Without this, the kinds of problems > you are seeing follow naturally from a misdirected solution. And your attempts to "solve" > it are completely off-base. > > If you are "losing" the object being dragged, it says there is a fundamental failure in > your algorithm, and tossing kludges at it isn't going to solve the fundamental problem. > Fix the fundamental problem. I have no idea what you are doing wrong, but the proposed > solution is, to say the least, nonsensical. > > You really have to CAREFULLY STUDY the Scribble tutorial; you have missed the fundamental > concepts of Windows graphics completely! > **** > >I don't know if it's the right way, but it's work fine.I thought also to manage > >the OnIdle thread, > **** > There is no such thing as "the OnIdle thread". There is an OnIdle handler which is called > in your main GUI thread if there is nothing else to do, but this is equally poor design to > use this for your redrawing. PLEASE study how graphics work in Windows; you are simply > kludging together hopelessly incorrect solutions otherwise. > **** > >but i don't know if it's better.Maybe the best could be > >crea
From: Dan Bloomquist on 18 Nov 2006 22:12
MarcoMB wrote: > Thanka a lot for your patience with me, i please you to understand i'm trying > to learn on myself Visual C++ studying on book etc, and it's not my true job, > i make it only for passion.So i tried to handle the static draw of my objects > in WM_PAINT message as you said, and it's ok, the solution was under my eyes > ... i'm going to studing Scribble carefully following your advice...and i'll > consider all your help like gold...unfortunately i based my app on a sample > tutorial i found on book that to mantain simple learning based the object on > CObArray, but i've read what you say that it's going wrong with those type of > generic object, and use instead template class that accept only specified > type of data object like CArray.I'll try to modify my simple paint > app...thanks a lot again. I have not looked at SRIBBLE in a while. Joe has gotten you see that OnDraw is where it happens. The only reason for drawing in OnMouseMove is that the mouse is captured and the window is on top. That makes it simple to eliminate flicker and use little processor time. The strokes are going into the container where it counts. You may want to use typedefs. For instance in OnDraw you will see: CTypedPtrList<CObList,CStroke*>& strokeList... The more often you do this the more often You commit to the specific container/method. In a header about drawing objects, (right after the CStroke declaration in this case): typedef CTypedPtrList<CObList,CStroke*> STROKELIST; Here is why. In the example the doc is the container. What happens when you want an independent generic container? You will soon have a class that is just that and the doc is only about file io. At that the doc could evolve to some 'project' io and know nothing about files. But you will want to caompartmitize this stuff to make your work OO. So you will: typedef CDrawingImage STROKELIST; And CDrawingImageContainer does what the doc did at first. What about the view? Same thing can apply. The view can become more generic and if the STROKELIST is snapped in, mouse moves can be relayed when enabled and: void CScribbleView::OnDraw(CDC* pDC) { //if attached/enabled strokeList.Draw( pDC ); //a one liner, and now it is windows portable. } Take a good look at OnDraw. The view really has nothing to do with drawing. It is done with the DC. What if you want your stuff to work with the WTL? It can without a breath. I am not trying to overwhelm you. But this is what c++ is really about. c++ is not an Object Oriented language, just an opportunity to program OO. Here is a simple implementation example of a class that works with MFC, WTL, and a plain old winmain: https://secure.codeproject.com/opengl/EGA.asp (the gagl class) Start with what Joe wrote. It is about how the API works, and it applies to all platforms as well as windows implementations. Best, Dan. |