Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PolyLine

15 views
Skip to first unread message

Luigino

unread,
Nov 5, 2009, 2:00:13 AM11/5/09
to
Hello everyone...

I'm trying to use CDC::PolyLine to draw some lines and I'm storing
values with:

typedef vector<POINT> points;
typedef vector<points> matrix_points;

matrix_points mPoints;
...
points singlepoints(mPoints[0]);
::PolyLine(&singlepoints, sizeof(singlepoints));

but it reports a conversion error on first parameter of PolyLine...
why?... that vector<POINT> is anyway an array of POINT....

Thanks to all
Ciao
Luigi

Giovanni Dicanio

unread,
Nov 5, 2009, 5:21:32 AM11/5/09
to

"Luigino" <npu...@rocketmail.com> ha scritto nel messaggio
news:cf656037-881e-44b7...@d10g2000yqh.googlegroups.com...

In the code you posted, you wrote ::PolyLine.
The :: prefix means that you are using a global function, so not the CDC
member function as you wrote in the beginning of your post.
Moreover, I think that the GDI function name is Polyline (not Poly*L*ine).
And CDC member function name is Polyline as well.
If you are using the global ::Polyline function, the first parameter should
be an HDC, not a pointer to an array.

Assuming that you are using CDC::Polyline (so, no :: prefix), your code
should be somthing like this:

dc.Polyline(
&singlepoints[0], // POINT * pPoints
singlepoints.size(), // int nCount
);

In fact, if you have an instance of STL std::vector and you want the pointer
to the first item (and items in std::vector are stored in contiguous memory
addresses as raw C vectors), you should use:

// std::vector< SomeType > v;
// Assume that 'v' is not empty
SomeType * ptr = &v[0];

and if you need the number of elements in the vector (not the total size in
bytes), you can use the size() method.

Giovanni

Luigino

unread,
Nov 5, 2009, 5:34:13 AM11/5/09
to
HI Giovanni,

first of all, thanks for your reply...
about the ::, I added it because it's in a CWnd base class so to call
the CDC::Polyline I had to add ::.
Anyway about the singlepoints:

I started with

matrix_points mPoints;

which is a array of arrays (multiple POINT list, like I have more than
one graph), and to get the first "line" of the list of POINT I coded:

points singlepoints(mPoints[0]);

which mPoints[0] is the first sequence of POINT for first graph so at
this point I should already have the POINT array...
Maybe I am wrong but looks like as you wrote:

&singlepoints[0]

is the first element of the array of POINT when Polyline wants the
entire array as defined in help document...
Or do I have missed/misunderstood something?....

Giovanni Dicanio

unread,
Nov 5, 2009, 7:33:32 AM11/5/09
to
"Luigino" <npu...@rocketmail.com> ha scritto nel messaggio
news:a73b2edb-1b6f-4610...@j19g2000yqk.googlegroups.com...

> first of all, thanks for your reply...

You are welcome.

> points singlepoints(mPoints[0]);
>
> which mPoints[0] is the first sequence of POINT for first graph so at
> this point I should already have the POINT array...
> Maybe I am wrong but looks like as you wrote:
>
> &singlepoints[0]
>
> is the first element of the array of POINT when Polyline wants the
> entire array as defined in help document...
> Or do I have missed/misunderstood something?....

I found this CDC::Polyline documentation on MSDN:

http://msdn.microsoft.com/en-us/library/bzaz1k1h%28VS.80%29.aspx

The prototype reads:

BOOL Polyline(
LPPOINT lpPoints,
int nCount
);

So, the first argument to the member function is a pointer to the first item
of the array of POINT's.
The second argument is the number of elements in the array.
Given

typedef std::vector<POINT> points;
points singlepoints ...

the above translates to:

1. &singlepoints[0] ( value for 'lpPoints' )
2. singlepoints.size() ( value for 'nCount' )

Giovanni

Luigino

unread,
Nov 5, 2009, 8:18:41 AM11/5/09
to
HI again Giovanni,

thanks again for your reply,

> I found this CDC::Polyline documentation on MSDN:
>
> http://msdn.microsoft.com/en-us/library/bzaz1k1h%28VS.80%29.aspx
>
> The prototype reads:
>
> BOOL Polyline(
> LPPOINT lpPoints,
> int nCount
> );
>

> typedef std::vector<POINT> points;
> points singlepoints ...
>
> the above translates to:
>
> 1. &singlepoints[0] ( value for 'lpPoints' )
> 2. singlepoints.size() ( value for 'nCount' )

Well but in the code when I type the method the tooltip reads as:

CClientDC dc(this); // to get device context of the class which is
based on CWnd
(dc.)BOOL CDC::Polyline(const POINT * lpPoints, int nCount);

I implemented a CClientDC because so I can get the device context of
the class which is based on CWnd, so in this case it's a pointer.
Actually I implemented like this:

dc.Polyline(reinterpret_cast<POINT*> (&singlepoints), singlepoints.size
())

so singlepoints would be converted from POINT * to const POINT *, it
compiles ok, and having some values to draw, it doesn't show anything
on the screen (I used a CPen with red color)...

Any suggest?...

Thanks again
Ciao
Luigi

Giovanni Dicanio

unread,
Nov 5, 2009, 8:59:24 AM11/5/09
to
"Luigino" <npu...@rocketmail.com> ha scritto nel messaggio
news:c8fc0f52-bd2c-423e...@m38g2000yqd.googlegroups.com...

> (dc.)BOOL CDC::Polyline(const POINT * lpPoints, int nCount);

> Actually I implemented like this:


>
> dc.Polyline(reinterpret_cast<POINT*> (&singlepoints), singlepoints.size
> ())

If 'singlepoints' is an instance of a std::vector<POINT> (as you wrote in a
previous post), the reinterpret_cast is unnecessary and wrong.
&singlepoints is the address of an instance of std::vector, which is wrong
in your above context.
Instead, you need a pointer to the first element of the vector, i.e.
&singlepoints[0] (assuming the vector is not empty).
In fact, the first argument of CDC::Polyline is a 'const POINT *'.

I repeat:

dc.Polyline( &singlepoints[0], singlepoints.size() );

is just fine.
Please read my previous post.

You can also verify with the following C++ FAQ:

http://www.parashift.com/c++-faq-lite/containers.html#faq-34.3

I verified also with a simple code snippet:

Create a MFC doc/view project with MFC app wizard, and paste this code in
the view class OnDraw() method:

<code>
typedef std::vector<POINT> Points;
Points points;
const int N = 5;
POINT pt;
int x1 = 10;
int x2 = 30;
int dx = (x2 - x1)/N;
int x = x1;

for (int i = 0; i < N; i++)
{
pt.x = x;
pt.y = 2*x;
points.push_back(pt);

x += dx;
}

pDC->Polyline( &points[0], points.size() );

</code>

Assuming that you add '#include <vector>' in "StdAfx.h", the above code
compiles fine and seems to me to run fine.

Giovanni

Luigino

unread,
Nov 5, 2009, 9:49:30 AM11/5/09
to
HI!

You're right....only now I got writing:

&v[0]

is like to pass the pointer's address of the array inside the vector,
like a car garage where to drive the car, you must get into the garage
first, and then start the car -- you don't "start the garage" to drive
the car.

In fact now it works! :-)

Thanks again Giovanni for your little support to make me understanding
this little detail about vectors :-)
Ciao
Luigi

Giovanni Dicanio

unread,
Nov 5, 2009, 11:50:46 AM11/5/09
to

"Luigino" <npu...@rocketmail.com> ha scritto nel messaggio

news:cd909f0c-7b44-40c3...@37g2000yqm.googlegroups.com...

Glad it worked.

Frankly speaking, from a personal style point of view, I would have
preferred a public method in std::vector (e.g. named something like ptr())
to return the pointer to the first element in the array, or NULL if the
vector is empty. I think that would be more clear than " &v[0] ".

Note that QVector container from QT library has that (it is called
QVector::data()).

Giovanni

Joseph M. Newcomer

unread,
Nov 5, 2009, 12:20:33 PM11/5/09
to
Note also that if you are drawing this outside your OnPaint handler, it can be arbitrarily
destroyed when something overlaps your window. The CClientDC dc(this) is always suspect
because it means you are not drawing in the OnPaint handler. While there are reasonable
times when this is exactly what you need to do, the nature of the question suggests you
are new at this, and therefore have missed the fact that the only guaranteed correct place
to do drawing is in the OnPaint handler. So I suggest you either explain why you are
drawing outside OnPaint or change your code so the drawing is done inside the OnPaint
handler.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Luigino

unread,
Nov 6, 2009, 11:14:08 AM11/6/09
to
HI Joe,

> Note also that if you are drawing this outside your OnPaint handler, it can be arbitrarily
> destroyed when something overlaps your window.  The CClientDC dc(this) is always suspect
> because it means you are not drawing in the OnPaint handler.  While there are reasonable
> times when this is exactly what you need to do, the nature of the question suggests you
> are new at this, and therefore have missed the fact that the only guaranteed correct place
> to do drawing is in the OnPaint handler.  So I suggest you either explain why you are
> drawing outside OnPaint or change your code so the drawing is done inside the OnPaint
> handler.

well in fact I am working in OnPaint handler.... just I have in it
something like if (condition) OnDraw();
where in the OnDraw I paint what I need and plus, yeah I figured out
CClientDC isn't workable, I had better to use CMemDC and it worked :-)
Now I have to finish to implement choice of graph type between lines
and bars, re-implement the code to re-adjust scale when resizing (in
the OnWindowsPosChanged event) and stuffs :-)

Surely I never finish to learn and having fun with MFC/Winapi hehe :-)

Ciao!
Luigi

Joseph M. Newcomer

unread,
Nov 6, 2009, 11:59:19 AM11/6/09
to
For the OnPaint handler, or OnDraw handler, you would use the DC provided (CPaintDC in the
OnPaint handler; the CDC * passed to the OnDraw handler). Then you will have the correct
DC.

It is usually considered tasteful to make sure you restore the DC to its original state
when you are done. The simplest way to do this is to use SaveDC and RestoreDC, rather
than keep dozens of little variables you have to remember to save and reset. For example

void CMyClass::DrawMyStuff(CDC * pDC)
{
int save = pDC->SaveDC();
CPen pen;
CBrush br;
... etc.
pDC->SelectObject(&pen);
pDC->SelectObject(&br);
pDC->SetBkMode(TRANSPARENT);
pDC->SetROP2(R2_XOR_PEN); // or some name like that...
... lots of drawing
pDC->RestoreDC(save);
}

Note that there was no attempt made anywhere to save the "old" state as the new state was
set, because it doesn't matter what the old state was. RestoreDC resets the state to what
it was on the SaveDC, so all those changes go away. And all the pens, brushes, etc. are
released from the DC, so upon exiting the scope, the destructors ~CPen, ~CBrush, etc.
actually delete their objects (note that an object that is selected into a DC cannot be
deleted, and the DeleteObject does not return an error code; it just doesn't do the
deletion. So you can leak GDI resources). The RestoreDC guarantees that the objects are
all deselected before their destructors execute.
joe

0 new messages