CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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

  2. #2
    Join Date
    Sep 2004
    Location
    Holland (land of the dope)
    Posts
    4,123

    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 ?

  3. #3
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,654

    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*
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are, by
    definition, not smart enough to debug it.
    - Brian W. Kernighan

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    https://visualstudio.microsoft.com/vs

  4. #4
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    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

  5. #5
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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!

  6. #6
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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

  7. #7
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,654

    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?
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are, by
    definition, not smart enough to debug it.
    - Brian W. Kernighan

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    https://visualstudio.microsoft.com/vs

  8. #8
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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....

  9. #9
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,654

    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
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are, by
    definition, not smart enough to debug it.
    - Brian W. Kernighan

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    https://visualstudio.microsoft.com/vs

  10. #10
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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!

  11. #11
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    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

  12. #12
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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!

  13. #13
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Assigning Member Name from String

    Quote Originally Posted by jonathan.allen View Post
    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

  14. #14
    Join Date
    Jan 2011
    Location
    Durham, UK
    Posts
    23

    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

  15. #15
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    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

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured