Initialising a Listbox on a dialog

I have a ListBox on a dialog which has a CListbox member variable m_listbox.

The following code causes a debug assertion in CListBox::ResetContent.

CMyDialog dlg;
dlg.m_listbox.ResetContent();
dlg.m_listbox.AddString("test");
dlg.DoModal();
etc

I am modifying a project that was created by somebody else, so I created a small test app which does the above purely for debugging purposes and in my test project there is no assertion and the string appears in the listbox.

Are there any project properties which might cause this sort of behaviour?
mark_sAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jhanceCommented:
This is not how this is done.  The listbox is NOT a member of the CMyDialog class and so you can't call it's member functions like this.

It has an ID, let's say IDC_LIST.  In your CMyDialog's OnInitDialog() member function, do this:

CListBox *pList = (CListBox*)GetDlgItem(IDC_LIST);
pList->ResetContent();
pList->AddString("test);

Your original InitInstance() function should just be:

CMyDialog dlg;
dlg.DoModal();

The OnInitDialog() get called by DoModal before the dialog is displayed.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mark_sAuthor Commented:
jhance,

thanks for your answer, but I don't see the point of using the class wizard to assign a CListBox member to the control ID of the listbox if you can't access it? Aren't they used by the data exchange mechanisms?

So in OnInitDialog, couldn't I access m_listbox directly?

Mark
0
jhanceCommented:
How have you created the dialog?  In the dialog editor?  If so, use the control ID.

Let me ask you this:  How does your CMyDialog get a member variable m_listbox?  Have you declared it in the class declaration for CMyDialog?  If so, then you do have a m_listbox class instantiated in your CMyDialog but how then do you get it to appear in the dialog window?

If you are doing something strange here, please post some of your code.  In general, however, you just create the CListBox item in your dialog eith the dialog editor and then operate on it like I've shown after getting it's handle using GetDlgItem.
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

jhanceCommented:
I've been rereading your question trying to understand what you are doing.

I gather that you have something like this:

class CMyDialog : public CDialog{
....
  CListBox m_ListBox;
....
};

If so, this does create an instance of a CListBox class in your dialog class but it does not create a CListBox window in your dialog window.  Don't miss the distinction between "class" and "window", they are NOT the same thing.  Now it is possible to cause such a box to be displayed, but you must call it's Create member function first at some point in your program AFTER the dialog window has been created.

I think you are calling ResetContent BEFORE there is a CListBox window existing to handle the message that is sent to it for the reset.
0
mark_sAuthor Commented:
jhance,

more info for you...

I created the dialog in the dialog editor, and dropped a listbox onto it (IDC_MYLISTBOX).

I then used class wizard, member variables tab, Add Variable button to attach a member variable  m_listbox ( category Control, variable type CListBox) to IDC_MYLISTBOX.

Classwizard adds the following to my class definition

// Dialog Data
//{{AFX_DATA(CMyDialog)
enum { IDD = IDD_MYDIALOG };
CListBox      m_listbox;
//}}AFX_DATA

and the following to my .cpp

void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyDialog)
DDX_Control(pDX, IDC_MYLISTBOX, m_listbox);
//}}AFX_DATA_MAP
}

so I don't understand why in CMyDialog's OnInitDialog() I should use

CListBox *pList = (CListBox*)GetDlgItem(IDC_LIST);
                                    pList->ResetContent();

when I could just use

m_listbox.ResetContent();

 
I have successfully used m_listbox in a small test app, but am having difficulty modifying somebody else's project (see initial question)

thanks,
Mark
0
jhanceCommented:
You cannot do m_listbox.ResetContent() in your OnInitDialog because m_listbox does NOT refer to the listbox control that you've added to the dialog in the dialog editor.  Please go back and re-read my earlier comments on windows vs. classes.  If you want to call ResetContent on the one that is in the dialog, then you use GetDlgItem to get a pointer to it and then you can call ResetContent on it:

CListBox *pList = (CListBox*)GetDlgItem(IDC_LIST);
                                    pList->ResetContent();

Again, there is NO inherent or implied relationship between a CListBox class that you add to your CMyDialog class and a listbox control you add to your dialog in the dialog editor.  Remember classes are not windows and windows are not classes.  A CListBox class just provides a convenient way to send window messages to a list box control but you must get the CListBox class pointer to point to a valid listbox control window before you can do anything with it.

0
mark_sAuthor Commented:
jhance,

>You cannot do m_listbox.ResetContent() in your OnInitDialog

but I'm doing it and it works.
0
jhanceCommented:
You said:

The following code causes a debug assertion in CListBox::ResetContent.

That tell me it's not working!  

Is there more to this tale than you're telling?
0
jhanceCommented:
Another note.  If you were to examine the cause of the assertion you are seeing, you will discover that it is due to sending a LB_RESETCONTENT message to a non-existent window.  MFC traps such calls for you when you have linked with the debug library.  If you run this code with the release libs, you will get a fatal exception.
0
mark_sAuthor Commented:
jhance,

This is my problem exactly. For the project that I'm modifying I get the assertion.

I knocked up a small test app for debugging purposes and m_listbox.ResetContent() (and AddString()) work OK - no assertion, and the string I've added is in the Listbox on my dialog when it appears.

My original question was what might be the difference in the project properties.
0
jhanceCommented:
I don't know.  Without seeing the code in your test app, I can't say for sure why it works.
0
jhanceCommented:
How about you send me the code for your test project that does work and I'll see if I can figure out what you did right.

My email is jwh20@hotmail.com
0
mark_sAuthor Commented:
OK, I'll send you the project when I get into work tomorrow. thanks.
0
GlennDeanCommented:
jhance is 100% correct.  BUT here is some info that may be related to your question.  First note that CListBox inherits CCmdTarget, so that's your clue m_listbox is associated with a window (and a window that accepts messages).
  The reason you're getting the debug assertion when you call ResetContent appears to be because you have not attached a window to m_listbox.  To do this you must call
  m_listbox.Create(dwStyle,rect,"parent window",id).  
   Follow this by a call to InitStorage to allocate space for the entries in your listbox.
   But, as jhance said, actually doing the above will do nothing to relate your m_listbox to the list box window on the dialog.
   If I read the series of comments correctly, it sounded like you got a string to appear on the screen - that can't be right?
       Glenn
0
GlennDeanCommented:
Forgot to put this in the above comment. I tried the above code, i.e. adding a call to Create and InitStorage, and then called ResetContent and AddString and it worked.  BUT, as soon as I went dlg.DoModal() an exception was thrown.
0
jhanceCommented:
Mark,

In the project you sent, here is why it works:

void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CMyDialog)
      DDX_Control(pDX, IDC_LIST1, m_listbox);
      //}}AFX_DATA_MAP
}

The DDX_Control creates the releationship between the IDC_LIST1 dialog control and the m_listbox CListBox class in your dialog implicitly.  You probably did this in the ClassWizard.

The next effect between:

DDX_Control(pDX, IDC_LIST1, m_listbox);

and

CListBox *pList = (CListBox *)GetDlgItem(IDC_LIST1);

is virtually identical.  In either case, you now have the class (or pointer to the class) associated with the IDC_LIST1 control in your dialog.

Regards,

Joe
0
mark_sAuthor Commented:
Joe,

Thanks for your help.

Mark
0
jhanceCommented:
Thanks.

So what was the bottom line on the project that _didn't_ work?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.