-
November 4th, 2011, 07:05 AM
#1
Assigning Member Name from String
Hi guys,
I have a little query for you that I haven't been able to find a solution for.
I want to set the name of a member by referencing a string. To me this seems like quite a straightforward thing to do, but I can't figure it out.
To be more specific to my problem, I'm using MFC C++ to draw an image through OnDraw and have a set of many pen colours and want to choose the pen colour depending on a position within an array, so here's a little snippet of what I have now and what I want:
void CPaintPicture::OnPaint()
{
CPaintDC dc(this);
OnDraw(&dc);
}
void CPaintPicture::OnDraw(CDC* pDC)
{
CPen pen1, pen2, pen3, pen4;
CPen* pOldPen;
CString penName;
pen1.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
pen2.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
pen3.CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
pen4.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
for(int i = 0; i < 4; i++)
{
// enablePen is a bool array defined elsewhere
if(enablePen[i] == TRUE)
{
// this is what I have now
if(i == 0) pOldPen = pDC->SelectObject(&pen1);
else if(i == 1) pOldPen = pDC->SelectObject(&pen2);
else if(i == 2) pOldPen = pDC->SelectObject(&pen3);
else pOldPen = pDC->SelectObject(&pen4);
// this is what I want (or something like this which actually works!)
penName.Format(_T("pen%d"), i + 1);
pOldPen = pDC->SelectObject(penName); // this is wrong, but I can't work out what to do!
}
}
...
}
So the last line I've given is where I try to assign the name of pOldPen using the string penName, any ideas how it's supposed to be done?
Many thanks,
Jonathan
-
November 4th, 2011, 07:15 AM
#2
Re: Assigning Member Name from String
Code:
// this is what I have now
if(i == 0) pOldPen = pDC->SelectObject(&pen1);
else if(i == 1) pOldPen = pDC->SelectObject(&pen2);
else if(i == 2) pOldPen = pDC->SelectObject(&pen3);
else pOldPen = pDC->SelectObject(&pen4);
Why isn't pen an array ?
-
November 4th, 2011, 07:24 AM
#3
Re: Assigning Member Name from String
As you can see here http://msdn.microsoft.com/en-us/libr...7h(VS.80).aspx using a string is not an option. SelectObject needs a pointer to one of the pens you have created.
Skizmos answer is of course the obvious solution on how to translate from the number to a CPen*
-
November 4th, 2011, 07:28 AM
#4
Re: Assigning Member Name from String
Perhaps you'll consider using map (for instance CMap<CString, LPCTSTR, CPen, CPen&>) rather than
Code:
CPen pen1, pen2, pen3, pen4;
Then you could do (pseudo-code, I didn't try to compile it!):
Code:
CMap<CString, LPCTSTR, CPen, CPen&> penMap;
// fill in the map
CString penName;
for(int i = 0; i < 4; i++)
{
penName.Format(_T("pen%d"), i + 1);
penMap.SetAt(penName, CPen(PS_SOLID, 1, RGB(xxx, yyy, zzz));)
...
}
and then use CMap::Lookup to obtain the CPen* pointer from the map using some generated penName...
Victor Nijegorodov
-
November 4th, 2011, 07:57 AM
#5
Re: Assigning Member Name from String
Of course! Why didn't I think of that?!
I've created an array of pens, however VS doesn't like me setting the array as:
for(int i = 0; i < 4; i++)
{
penArray.SetAt(i, CPen(PS_SOLID, 1, RGB(xxx, yyy, zzz)));
}
I get the error:
c:\program files\microsoft visual studio 8\vc\atlmfc\include\afxwin.h(280) : error C2248: 'CObject:: operator =' : cannot access private member declared in class 'CObject'
c:\program files\microsoft visual studio 8\vc\atlmfc\include\afx.h(559) : see declaration of 'CObject:: operator ='
c:\program files\microsoft visual studio 8\vc\atlmfc\include\afx.h(529) : see declaration of 'CObject'
This diagnostic occurred in the compiler generated function 'CGdiObject &CGdiObject:: operator =(const CGdiObject &)'
I know this is due to how I'm creating the pen, so will fix this then all will be well!
Thanks guys!
-
November 4th, 2011, 08:03 AM
#6
Re: Assigning Member Name from String
For those who also get the final error I mentioned, I found this solution to edit the class constructor to permit this solution to work:
http://stackoverflow.com/questions/8...r-using-carray
-
November 4th, 2011, 08:13 AM
#7
Re: Assigning Member Name from String
Don't go that way! There's probably a very good reason for MS to make the CObject non-copyable. You don't think they made it like that just to be evil do you?
Instead you have to adapt to it by going some other way. Maybe by making the array contain smart pointers to the CPen objects instead?
-
November 4th, 2011, 08:32 AM
#8
Re: Assigning Member Name from String
There are many times I think they made it certain ways to be evil!
Ok, seriously, I'll not do it this way if you think this, smart pointers are something I haven't come across before but I'll do some research into them and try to implement in that way instead, your suggested method makes sense so I can't forsee any issues I'll have with it....
-
November 4th, 2011, 08:52 AM
#9
Re: Assigning Member Name from String
I don't think there's support for a shared pointer in VC2005 but you can use boost instead. See this http://www.boost.org/doc/libs/1_47_0...shared_ptr.htm
-
November 4th, 2011, 09:19 AM
#10
Re: Assigning Member Name from String
Yes, I've been having a look at that myself, it'll take me some time to through it, but for now I've applied the following quick fix so my program can run while I'm reading:
Code:
CArray<CPen*, CPen*> penArray;
CPen pen1, pen2, pen3, pen4;
CPen* pOldPen;
CString penName;
pen1.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
pen2.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
pen3.CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
pen4.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
penArray.SetAtGrow(0, &pen1);
penArray.SetAtGrow(1, &pen2);
penArray.SetAtGrow(2, &pen3);
penArray.SetAtGrow(3, &pen4);
for(int i = 0; i < 4; i++)
{
if(enablePen[i] == TRUE)
{
pOldPen = pDC->SelectObject(penArray[i]);
penName.Format(_T("Pen %d"), i + 1);
}
}
It's not pretty, but it does the job for now. Once I've got myself clued up on smart pointers I'll change all this to suit it.
Thanks for your help!
-
November 4th, 2011, 09:27 AM
#11
Re: Assigning Member Name from String
Sorry, but I don't see any advantage in this piece of code comparing with
Code:
CPen* pOldPen;
CString penName;
CPen pen[4];
pen[0].CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
pen[1].CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
pen[2].CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
pen[3].CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
for(int i = 0; i < 4; i++)
{
if(enablePen[i] == TRUE)
{
pOldPen = pDC->SelectObject(&pen[i]);
penName.Format(_T("Pen [%d]"), i );
}
}
Victor Nijegorodov
-
November 4th, 2011, 09:51 AM
#12
Re: Assigning Member Name from String
Victor, you're quite right, your way of defining the way is how I should do it rather than the quick fix I described - I took the idea of a "quick" fix too literally and didn't think to simply define the CPen object as the array! I've done that now and it's working nicely, cheers!
-
November 4th, 2011, 10:08 AM
#13
Re: Assigning Member Name from String
Originally Posted by jonathan.allen
Yes, I've been having a look at that myself, it'll take me some time to through it, but for now I've applied the following quick fix so my program can run while I'm reading:
You're not understanding what the issue is. The issue is copying CPen objects. Using an array of CPen does not imply that you're going to make copies. In VictorN's example, he is not copying CPen objects -- if he did, the compiler would not let that code go through as the copy constructor is disabled in CObject (the parent of CPen).
The basic issue you had is that you assumed that a CArray is an array -- it is not an array. A CArray is a class that serves as a dynamic array.
An array in C++ has a specific meaning:
Code:
int x[10]; // an array of 10 integers
double d[4]; // an array of 4 doubles
CPen p[4]; // an array of 4 pens
An array is declared using the [] syntax, cannot be resized. You never used a regular array, but instead kept using CArray and assuming this is an array. If you know the number of items in the array, and the number will never change at runtime, then use a regular array.
As to CArray, there is no such thing in C++ as a "native" dynamic array. A dynamic array has to be simulated by creating a class, and that class in MFC is CArray (in standard C++ it is std::vector). So to have the functionality of a dynamic array, copies must be made of the objects when shuffling items around in the array to make room for other entries. That's why you get the compiler error -- the CArray needed to make copies of the CPen to increase the size of the container by 1.
The only similarity between a CArray and a regular array is that you can use the [] syntax to access the elements, and that internally, CArray stores its data in contiguous memory, just like an array. Therefore you can pass the internal buffer of the CArray to functions normally reserved for "regular" arrays.
If you want to get really technical, if you have VS 2008 SP1 or above, you can use this:
Code:
#include <array>
std::tr1::array<CPen,4> PenArray; // for VS 2008 SP1
// std::array<CPen,4> PenArray; // for VS 2010 and above
this declares an STL array of 4 pens. This is a class that actually does wrap a "true" array. So Victor's code could be written like this:
Code:
#include <array>
std::array<CPen,4> pen;
pen[0].CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
pen[1].CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
pen[2].CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
pen[3].CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
Assuming you have VS 2010.
But that is not needed in this case, and just a regular array is all that's necessary.
Regards,
Paul McKenzie
-
November 4th, 2011, 10:17 AM
#14
Re: Assigning Member Name from String
Paul,
Thank you for your extensive explanation, I understand what you mean, and you're right in the mistake I was making, forgetting what "CArray" really means, now that you've reminded me I can see why I was generating the compiler error.
I'm running VS2005 and the method Victor posted is working fine.
Returning to my original question, is there a method of using the text within a string to define the name of a variable (not necessarily a CPen, maybe a double etc.), simply out of my personal interest?
Thanks,
Jonathan
-
November 4th, 2011, 02:39 PM
#15
Re: Assigning Member Name from String
is there a method of using the text within a string to define the name of a variable (not necessarily a CPen, maybe a double etc.), simply out of my personal interest?
No there is not in C++, and other compiling languages won't let that either. The trick is allowed in scripting languages only. The explanation is very simple: your dynamic var name is going to be defined only at runtime, while compiler needs that at compile time. And after compilation there are no names kept for late binding of any kind.
Last edited by Igor Vartanov; November 4th, 2011 at 02:45 PM.
Best regards,
Igor
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|