From: Joseph M. Newcomer on
See bekiw,,,
On Wed, 10 Feb 2010 00:18:02 -0800 (PST), Luigino <npuleio(a)rocketmail.com> wrote:

>Hi again Joe,
>
>On the other hand I tried to set your suggest about point origin then
>I tried to draw a red line at bottom, which it should supposed to with
>this code:
>
>void CMyDLL::PrepareDC(CDC & dc)
>{
> CRect rc;
> dc.GetClipBox(&rc);
>
> switch (iGraphType)
> {
> case GRAPH_BARS:
> {
> //dc.Rectangle()
> }
> break;
>
> case GRAPH_LINES:
> {
> ::SetGraphicsMode(dc, GM_COMPATIBLE);
> dc.SetMapMode(MM_ANISOTROPIC);
> dc.SetWindowExt(-rc.Width(), 32767);
> dc.SetViewportExt(rc.Width(), -rc.Height());
> dc.SetWindowOrg(rc.Width(), 0);
> dc.SetViewportOrg(-rc.Width(), 0);
>
> //dc.SetWindowExt(rc.right, 32767);
> //dc.SetViewportExt(-rc.right, -rc.bottom);
> //dc.SetWindowOrg(rc.right, 4988);
> //dc.SetViewportOrg(0, 0);
>
> CPen qZeroPen( PS_SOLID, 2, RGB(255, 0, 0) ); /
>* red pen to check what's the 0 coordinate */
****
Note that when you leave scope, you will call the destructor of this pen, but it is still
selected into the DC, so you will leak GDI resources.
****
> dc.SelectObject(&qZeroPen);
> dc.MoveTo(rc.left, rc.Height());
> dc.LineTo(rc.right,
>rc.Height());
> }
> break;
>
> default:
> break;
> }
>}
>
>but it doesn't even appear... tried also with rc.top and 0 (which
>should mean drawing the line at the top of the client rect) but
>nothing...
****
Try drawing an "X". This has the advantage that it will not be hidden or clipped by the
edges of the rectangle.

Note that a rectangle will always be one pixel smaller than its width would suggest,
because all graphics in GM_COMPATIBLE mode are up-to-but-not-including the endpoint.

You chose the wrong way to illustrate this issue. Drawing a single line at the border
doesn't really guarantee you will see it.
****
>And I'm creating the graphic control in the whole client rect of the
>CDialog test application:
>
>CRect rect;
>GetClientRect(&rect);
>CStatic MyStaticControl;
>
>MyControl.Create( this, &MyStaticControl, rect,
>MyStaticControl.GetDlgCtrlID() );
****
Since the scope of MyStaticControl is local here, the control will be destroyed when you
leave this scope. The control must be declared as a member variable of the dialog.

Since you are declaring only a single static control, why are you creating it at runtime,
anyway? You can create it at design time.

How is it that you can call GetDlgCtrlID() on a control which does not exist? This should
give you assertion failures. It obviously makes no sense; you are asking for a control ID
of a variable which HAS NO CONTROL!

****
>
>which would mean the graphic is drawn all inside the CDialog form....
>
>that's weird...
>
>Any hint?...
****
Create the control at design time. There is no reason to create it at run time as you are
doing. The whole idea doesn't make any sense. Or your example is not telling us what is
*really* going on.
joe
****
>Thanks
>Ciao
>Luigi
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
See below...
On Wed, 10 Feb 2010 09:06:20 -0800 (PST), Luigino <npuleio(a)rocketmail.com> wrote:

>Hello Steve,
>
>> dc.SetWindowExt(-rc.Width(), 32767);
>> rc.width() has nothing whatsoever to do with your data. How many
>> samples have you taken? What is the LOGICAL width of the graph?
>
>I set X logical extent as the same of rc.width() because I have an
>array with dimension of the desktop screen but I visualize on the
>screen only recent data from right to left because everytime I add a
>new element I execute a rotation of the array to add newest element at
>the end. In this way if I maximize the window which shows more data I
>can show more data. If datas goes like "outside the desktop" then they
>are considered like lost, that's the reason of the rotation...
****
I see no examples of "rotation" here. Rotation is a transposition of the x-y coordinate
system. What you are talking about here is *scrolling*, and you scroll the values off the
end and lose them. But this isn't related to the logical coordinate system.
****
>For this I have this objective to set the origin at bottom-right so if
>I have those array logical values example:
>
>{ x=0 y=0; x=1 y=11423; x=2 y=3343; x=3 y=7543;...; x=122 y=432;
>x=123 y=27432 }
>
>Polyline would apply this logical array from right to left translating
>in device points obtaining a graphic that starts from the bottom-right
>corner showing an entire line at y=0 (in the bottom) then showing new
>elements in queue from right to left...
>Like if Polyline in that moment reads x=123 y=27432 this point would
>be represented at x=123 from right to left somewhere on Y between 0
>and rc.Height() based on "translation extent"...
>
>Plus I was thinking about playing directly with logical values from
>source because since it's an array which at creation of the canvas is
>filled with zeros as Y and if I do a DPtoLP when I haven't mapped yet
>the canvas it would produce different value...
****
It is not at all clear why you would need to do a DPtoLP unless you are translating mouse
coordinates to logical coordinates. You keep making this problem much harder than it
needs to be by introducing all these unnecessary concepts.

For example, consider the scrolling issue. One simple way to handle this is to simply
remove the first element of the array (this will then recompact the array to fill in the
hole) and adding the new element at the end of the array. Then call Invalidate() and it
will redraw.

Of course, in this case it will redraw with the grid in a fixed position, so the graphics
will move behind a fixed grid. You can also provide a way to compute the grid offset so
the grid also slides left as the values scroll off. It depends on what kind of meaning
the grid lines have.

But if your samples are just sequential values, then you would typically not store the
x-coordinate at all; you would have an array of x-y pairs were x had no meaning until the
OnPaint handler, at which point you would race through the array from 0 to n and set x to
the index value of the array. Each time you removed an element from the 0th position of
the array, the elements would be numbered 1..n, and the next time you drew, they would be
numbered 0..n because you would have added a new element on the end of the array.

On the other hand, if you wanted to keep them so they could be re-examined, you would keep
the entire array. Or you could keep a "recent history" so the user could scrolll back a
few "pages" of the image, but after that the data would be lost.

I did something like this when I was doing a medical graphic application; in Win16, we
couldn't hold all the data, so I reduced it to a few pages before and after the window
that was being shown. As the user scrolled forward, I removed elements from the front and
added them to the back. Furthermore, to reduce storage requirements and improve
performance, if I found that several x (logical) coordinates mapped to the same x (device)
coordinate, I just set the point to be the min or max (negative, min, positive, max) of
the value found. Got tremendous performance on 100MHz 486-class machines. But I created
a complex solution because I got such good performance. You don't have anything nearly
that complex, and creating complex solutions isn't going to help much.

First: it is very rare that you need to create controls at runtime. Avoid this whenever
possible. I see no reason it is necessary here. Any control that is a subclass of
CStatic can be created at design time.

Second: Make sure that at the end of a scope that defines GDI objects that the GDI objects
are all deselected from the DC. Use SaveDC/RestoreDC to ensure this

Third: DPtoLP and LPtoDP are used in very limited contexts. Don't use them unnecessarily

WIthout studying the code in more detail, I don't see where it is going wrong at this
point.
joe
****
>
>Thanks
>Ciao
>Luigi
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
I plugged the numbers into the Viewport Explorer and realized the numbers you gave below
are wrong.

Here's the correct code:

SetWindowExt(-rc.Wdith(), 32767) // you had this right
SetViewportExt(rc.Width(), -rc.Height()) // you had this right
SetWindowOrg(rc.Width(), 0); // you had this right
SetViewportOrg(0, rc.Height()); // this was completely wrong

Note that Viewport Explorer limits the coordinates to 5000, but you can see when you move
the mouse over the display area that you will see that the coordinates work correctly.
joe


On Wed, 10 Feb 2010 00:18:02 -0800 (PST), Luigino <npuleio(a)rocketmail.com> wrote:

>Hi again Joe,
>
>On the other hand I tried to set your suggest about point origin then
>I tried to draw a red line at bottom, which it should supposed to with
>this code:
>
>void CMyDLL::PrepareDC(CDC & dc)
>{
> CRect rc;
> dc.GetClipBox(&rc);
>
> switch (iGraphType)
> {
> case GRAPH_BARS:
> {
> //dc.Rectangle()
> }
> break;
>
> case GRAPH_LINES:
> {
> ::SetGraphicsMode(dc, GM_COMPATIBLE);
> dc.SetMapMode(MM_ANISOTROPIC);
> dc.SetWindowExt(-rc.Width(), 32767);
> dc.SetViewportExt(rc.Width(), -rc.Height());
> dc.SetWindowOrg(rc.Width(), 0);
> dc.SetViewportOrg(-rc.Width(), 0);
>
> //dc.SetWindowExt(rc.right, 32767);
> //dc.SetViewportExt(-rc.right, -rc.bottom);
> //dc.SetWindowOrg(rc.right, 4988);
> //dc.SetViewportOrg(0, 0);
>
> CPen qZeroPen( PS_SOLID, 2, RGB(255, 0, 0) ); /
>* red pen to check what's the 0 coordinate */
> dc.SelectObject(&qZeroPen);
> dc.MoveTo(rc.left, rc.Height());
> dc.LineTo(rc.right,
>rc.Height());
> }
> break;
>
> default:
> break;
> }
>}
>
>but it doesn't even appear... tried also with rc.top and 0 (which
>should mean drawing the line at the top of the client rect) but
>nothing...
>And I'm creating the graphic control in the whole client rect of the
>CDialog test application:
>
>CRect rect;
>GetClientRect(&rect);
>CStatic MyStaticControl;
>
>MyControl.Create( this, &MyStaticControl, rect,
>MyStaticControl.GetDlgCtrlID() );
>
>which would mean the graphic is drawn all inside the CDialog form....
>
>that's weird...
>
>Any hint?...
>Thanks
>Ciao
>Luigi
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Luigino on
HI Joe,

> Note that when you leave scope, you will call the destructor of this pen, but it is still
> selected into the DC, so you will leak GDI resources.

> ****> dc.SelectObject(&qZeroPen);

When the pen destroys, shouldn't also be automatically unselected from
the DC?.... (just asking because I thought something about unselecting
but haven't found any "UnSelectObject" or "DeselectObject"...)

> >but it doesn't even appear... tried also with rc.top and 0 (which
> >should mean drawing the line at the top of the client rect) but
> >nothing...
>
> ****
> Try drawing an "X". This has the advantage that it will not be hidden or clipped by the
> edges of the rectangle.
>
> Note that a rectangle will always be one pixel smaller than its width would suggest,
> because all graphics in GM_COMPATIBLE mode are up-to-but-not-including the endpoint.
>
> You chose the wrong way to illustrate this issue. Drawing a single line at the border
> doesn't really guarantee you will see it.

After I corrected the SetViewportOrg() as you said, I tried to
implement first:

dc.MoveTo(rc.right, 32767);
dc.LineTo(rc.left, 32767);

I see a horiz red line at the TOP of the client area; then I
implemented this:

dc.MoveTo(rc.right, 0);
dc.LineTo(rc.left, 0);

which should be the BOTTOM of the client area, and it doesn't show at
all, so to check I did first:

dc.MoveTo(rc.right, 25000);
dc.LineTo(rc.left, 0);

I see the line diagonally from LEFT side at 25000 to RIGHT side at 0
which presumably it is in some invisible part of the area... weird. So
I checked again:

dc.MoveTo(rc.right, 300);
dc.LineTo(rc.left, 0);

and here I see a diagonal line from LEFT side at 300 to RIGHT side
somewhere under the bottom line of the rectangle which it's weird. At
creation I passed CDialog's rect where to draw the area on so I
suppose it should be drawn at the VISIBLE canvas (which should be that
dotted rectangle in design time I see on a form) but this makes me
thinking the control is created on the whole rect of the CDialog
hiding some part under those borders of the canvas...

> ****
> Since the scope of MyStaticControl is local here, the control will be destroyed when you
> leave this scope. The control must be declared as a member variable of the dialog.

In fact it's declared in fact as a member variable as:

public:
CStatic MyStaticControl;

> Since you are declaring only a single static control, why are you creating it at runtime,
> anyway? You can create it at design time.
> Create the control at design time. There is no reason to create it at run time as you are
> doing. The whole idea doesn't make any sense. Or your example is not telling us what is
> *really* going on.

About what you've said to draw it at design time, I don't know if from
a DLL it is possible to draw this object class as a control and the
CMyDLL class is CWnd based...

> How is it that you can call GetDlgCtrlID() on a control which does not exist? This should
> give you assertion failures. It obviously makes no sense; you are asking for a control ID
> of a variable which HAS NO CONTROL!

You're right...that was to assign ID to the Create parameter
"nparentID" but I just figured I have to assign a total new UINT
id...

****
I see no examples of "rotation" here. Rotation is a transposition of
the x-y coordinate
system. What you are talking about here is *scrolling*, and you
scroll the values off the
end and lose them. But this isn't related to the logical coordinate
system.
****

Well... I meant rotation of the array as like all the whole array is
shifted left so I could add new element to the last position as you
can see here:

rotate( myarray[idx].begin(), myarray[idx].begin()+1,
myarray[idx].end() );
myarray[idx].at(myarray[idx].size() - 1) = -(LONG)rand();

Thanks
Ciao,
Luigi
From: Joseph M. Newcomer on
See below...
On Thu, 11 Feb 2010 06:11:33 -0800 (PST), Luigino <npuleio(a)rocketmail.com> wrote:

>HI Joe,
>
>> Note that when you leave scope, you will call the destructor of this pen, but it is still
>> selected into the DC, so you will leak GDI resources.
>
>> ****> dc.SelectObject(&qZeroPen);
>
>When the pen destroys, shouldn't also be automatically unselected from
>the DC?.... (just asking because I thought something about unselecting
>but haven't found any "UnSelectObject" or "DeselectObject"...)
****
No. You have it backwards. There is no "automatic deselection" and the concept does not
exist. Instead, what happens is that the DC retains a pointer to the graphics object,
which does not go away. Then, when the DC is destroyed, the object no longer has any
application-visible reference, and therefore cannot be deleted.

The way you handle this is to either re-select the original object back into the DC, or
use SaveDC/RestoreDC to ensure the DC is restored to its pre-SaveDC state and therefore
any objects selected in are implicitly deselected. I find this preferable to the
old-fashioned approach of declaring tons of "old object" variables and having to remember
to restore them.
****
>
>> >but it doesn't even appear... tried also with rc.top and 0 (which
>> >should mean drawing the line at the top of the client rect) but
>> >nothing...
>>
>> ****
>> Try drawing an "X". This has the advantage that it will not be hidden or clipped by the
>> edges of the rectangle.
>>
>> Note that a rectangle will always be one pixel smaller than its width would suggest,
>> because all graphics in GM_COMPATIBLE mode are up-to-but-not-including the endpoint.
>>
>> You chose the wrong way to illustrate this issue. Drawing a single line at the border
>> doesn't really guarantee you will see it.
>
>After I corrected the SetViewportOrg() as you said, I tried to
>implement first:
>
>dc.MoveTo(rc.right, 32767);
>dc.LineTo(rc.left, 32767);
>
>I see a horiz red line at the TOP of the client area; then I
>implemented this:
>
>dc.MoveTo(rc.right, 0);
>dc.LineTo(rc.left, 0);
>
>which should be the BOTTOM of the client area, and it doesn't show at
>all, so to check I did first:
****
What part of "the right and bottom limits are off by one pixel" did you miss? I said that
extents of graphical objects are up-to-but-not-including, so the 0 point is not part of
the area that is drawable. It is one pixel beyond that area. You keep trying flawed
experiments and keep being surprised when they don't work. I said to draw an "X" for a
very good reason, and you just drew a straight line. It didn't work, and that isn't
surprising.
****
>
>dc.MoveTo(rc.right, 25000);
>dc.LineTo(rc.left, 0);
>
>I see the line diagonally from LEFT side at 25000 to RIGHT side at 0
>which presumably it is in some invisible part of the area... weird. So
>I checked again:
****
No, remember that you reversed coordinates. So x=0 is the right side of the rectangle,
and x = r.right means r.right positive logical units from (0,0), which of course is the
left edge. And what you probably saw was the line ended up at (0,0) but all that was
visible was (1,1). So it sounds like you were getting the expected result with this
experiment.
****
>
>dc.MoveTo(rc.right, 300);
>dc.LineTo(rc.left, 0);
>
>and here I see a diagonal line from LEFT side at 300 to RIGHT side
>somewhere under the bottom line of the rectangle which it's weird.
****
No, it did precisely the correct thing. Use Viewport Explorer and move the mouse over the
area defined by your coordinate system. You will see that the leftmost edge is x =
rc.right and the rightmost edge is x = 0.

Since it is doing what it is supposed to do, given your choices of coordinate system,
what's the problem?
****
>At
>creation I passed CDialog's rect where to draw the area on so I
>suppose it should be drawn at the VISIBLE canvas (which should be that
>dotted rectangle in design time I see on a form) but this makes me
>thinking the control is created on the whole rect of the CDialog
>hiding some part under those borders of the canvas...
****
Creation time is so completely irrelevant to drawing that I have no idea what you could
possibly be doing there. Are you saying that you use the client rectangle area of the
dialog as the creation rectangle of your static control? If so, then say it.
****
>
>> ****
>> Since the scope of MyStaticControl is local here, the control will be destroyed when you
>> leave this scope. The control must be declared as a member variable of the dialog.
>
>In fact it's declared in fact as a member variable as:
>
>public:
> CStatic MyStaticControl;
****
Note that it is critical that when you show a declaration, you must tell us where it is,
or we assume that it is inline in the code (that is, a local variable). But you still
have a local variable for the other CStatic.
****
>
>> Since you are declaring only a single static control, why are you creating it at runtime,
>> anyway? You can create it at design time.
>> Create the control at design time. There is no reason to create it at run time as you are
>> doing. The whole idea doesn't make any sense. Or your example is not telling us what is
>> *really* going on.
>
>About what you've said to draw it at design time, I don't know if from
>a DLL it is possible to draw this object class as a control and the
>CMyDLL class is CWnd based...
****
The DLL presumably creates the dialog, right? If it creates the dialog, then you can do
it at design time. If the DLL is just drawing into an existing control, then create the
control and just pass its CWnd* to the DLL.

You haven't really said who creates what when. Note that a DLL would not create a CWnd
and keep it in a variable local to the DLL because then you couldn't create more than one
of them.
****
>
>> How is it that you can call GetDlgCtrlID() on a control which does not exist? This should
>> give you assertion failures. It obviously makes no sense; you are asking for a control ID
>> of a variable which HAS NO CONTROL!
>
>You're right...that was to assign ID to the Create parameter
>"nparentID" but I just figured I have to assign a total new UINT
>id...
****
It is not uncommon that in exotic situations I will create a CStatic and give it an ID
other than IDC_STATIC. I will then use this static variable to define the area used by a
custom control created at runtime; I use the CRect of the control as the argument to
Create, and I use GetDlgCtrlID of the old static to assign the ID to the new control,
after which I call DestroyWindow on the old static control to get rid of the
"placeholder". But you did not indicate that this is what you are doing; instead, you
just toss in a random CStatic declaration that has no associated control and call a method
which requires a control.
****
>
>****
>I see no examples of "rotation" here. Rotation is a transposition of
>the x-y coordinate
>system. What you are talking about here is *scrolling*, and you
>scroll the values off the
>end and lose them. But this isn't related to the logical coordinate
>system.
>****
>
>Well... I meant rotation of the array as like all the whole array is
>shifted left so I could add new element to the last position as you
>can see here:
****
That is called "horizontal scrolling". Rotation does not enter the discussion.
****
>
>rotate( myarray[idx].begin(), myarray[idx].begin()+1,
>myarray[idx].end() );
>myarray[idx].at(myarray[idx].size() - 1) = -(LONG)rand();
****
As I said, horizontal scrolling. This is a classic horizontal scrolling technique.
joe
****
>
>Thanks
>Ciao,
>Luigi
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm