From: Joseph M. Newcomer on
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
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
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
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


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.