Click here to Skip to main content
15,889,861 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello everyone in the world of programming
I am confused by the problem for a long time: I create an ListBox control included in a Dialog,and use the Dialog object in another class T, and I want to add item(AddString) into the ListBox in the class T, but it always pops up
C#
debug which tells assertion failed when run.
  
Here is the brief structure:
   
   class A
  {
      CListBox m_listvalue;

     .......
  }

  class T
  {
  .....
    
   Myfunc()
   {
      A a;
     a.m_listvalue.addString("Calculative table : ");  
               //Explain: the program break out when come here
     ......
   }
  }

presentation:

Debug Assertion Failed!
...c:\T.exe
File:f:\dd\ve\vctools\vc7libs\ship\atlmfc\include\afxwin2.inl
Line: 810

For information on how your program can cause an assertion failure, see the
Visual C++ documentation on assers.

(press Retry to debug the application)



Anyone with idea can help or give related site。
Thanks you!


C++
//OutputDialog.h
class OutputDialog : public CDialog
{
// Construction
public:
	OutputDialog(CWnd* pParent = NULL);   // standard constructor
//	void UpdateList();
// Dialog Data
	//{{AFX_DATA(OutputDialog)
	enum { IDD = IDD_OUTPUTDIALOG };
	CListBox m_ListValue;
	//}}AFX_DATA

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(OutputDialog)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL
// Implementation
protected:
	// Generated message map functions
	//{{AFX_MSG(OutputDialog)
         virtual BOOL OnInitDialog();
	virtual void OnOK();
	virtual void OnCancel();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
	
//OutputDialog
};

C++
//OutputDialog.cpp

OutputDialog::OutputDialog(CWnd* pParent /*=NULL*/)
	: CDialog(OutputDialog::IDD, pParent)
{
	//{{AFX_DATA_INIT(OutputDialog)
	//}}AFX_DATA_INI
}

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

BEGIN_MESSAGE_MAP(OutputDialog, CDialog)
	//{{AFX_MSG_MAP(OutputDialog)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// OutputDialog message handlers

BOOL OutputDialog::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here

   // m_ListValue.CreateObject();

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void OutputDialog::OnOK() 
{
	
	// TODO: Add extra validation here
	 this->CloseWindow();
	
	CDialog::OnOK();
}

void OutputDialog::OnCancel() 
{
	// TODO: Add extra cleanup here
	if(this->MessageBox( "Are you sre",Message", MB_ICONQUESTION|MB_YESNO))
	{
           this->DestroyWindow();
	}

	CDialog::OnCancel();
}


And I instantiate the OutputDialog in the ShowTabelContend method:
C#
void ShowTabelContend()
 {
    OutputDialog outputDialog;

     //OutputDialog outputDialog = new OutputDialog();
     //   if(this->matrixtable && this->size != 0)        
    //   {       //Explain:  matrixtable and size is the element arialble in My data pass class
       //if((outputDialog != NULL))
    //  {

        //  char *Title = "Calculative table" :;
        //  outputDialog.m_ListValue.InsertString(1,Title);

            outputDialog.m_ListValue.AddString("Calculative table :");

        /*  for (int i = 1; i < 2 * this->size + 1; ++ i)
            {
               outputDialog.m_ListValue.InsertString(i * 5, 
                            (this->matrixtable + (i - 1) * 2 *this->size));
               outputDialog.m_ListValue.AddString(
                             (this->matrixtable + (i - 1) * 2 *this->size));
            }
        }*/
        outputDialog.UpdateData(false);
        outputDialog.DoModal();
        
    }

    return ;
}
Posted
Updated 2-Oct-11 6:12am
v8
Comments
Maximilien 2-Oct-11 10:34am    
You cannot add the string to the list box in the dialog before it (the dialog) is created by DoModal.

Pass the data to the dialog class and add the strings in the OnInitDialog.

I assume you are trying to fill the list box before it is created; and this will crash.

What is class A ? is it a class derived from CDialog ?
What is class T ?
what is the relation between the 2 classes T and A ?

Instantiating a listbox is not sufficient to add items to it, you must also create the Windows window for it (CListBox::Create) which is done automatically by the OnInitDialog.

(in your example) The list box belongs in a dialog. the listbox will be accessible to be filled after the dialog's OnInitDialog is done.

for example you can have something like this (pseudo-ish code)

C++
std::vector<string> someData; // vector containing string to be put in the listbox
YourDialog dlg;
dlg.PutData( someData);
dlg.DoModal().
</string>


C++
class YouDialog : public CDialog
{
  std::vector<string> m_SomeData;
  CListBox m_ListBox;
  void PutData( std::vector<string> someData){m_SomeData = someData;};
  BOOL OnInitDialog();
};

BOOL YourDialog::OnInitDialog()
{
  BOOL ret = __super::OnInitDialog();
  // from this point the list box is created and valid to be used.
  for ( int i = 0; i < m_SomeData.size(); i++ )
  {
    m_ListBox.AddString( m_SomeData[i] );
  }
  return ret;
}
</string></string>
 
Share this answer
 
Comments
Chuck O'Toole 2-Oct-11 0:15am    
He's still going to need a DDX_Control statement in DoDataExchange() to properly subclass m_ListBox. void YouDialog::DoDataExchange(CDataExchange* pDX) { _super::DoDataExchange(pDX); DDX_Control(pDX, IDC_xxxxxxxx, m_ListBox); } Where IDC_xxxxxxxx is the value given to the specific GUI control by the Dialog Editor (PS, why doesn't code paste properly in these comment windows? It started out nicely aligned until I hit 'submit' then it turned to unreadable crap)
Albert Wen-Jie Feng 2-Oct-11 6:46am    
Thank you.
The structure of my program is that the dialog is the output dialog for my data, and the ListBox Control named as m_listvalue is a part of the dialog which is used as showing data. And the data is created or generated in the class T. So I create an object of the dialog in class T, and add data serially into the m_listvalue. when the program carry out to AddString(data), it breaks out. Also I use the MFC to create the dialog class.
How do I deal with the problem?
Thank you!!
Chuck O'Toole 2-Oct-11 6:58am    
There are at least 3 ways of doing anything in Windows. Creating and displaying Dialogs are no different. Your words don't tell us *how* you created the dialog, just that you used MFC do to it. Your original question showed very little of your windows startup code, I assume there is a lot more or your dialog would not display (at least I'm assuming it is displaying properly even if the part about putting data into the list is blowing up). As this Solution shows, there should be OnInitDialog, etc. Please show us that. Otherwise we'll just keep asking questions without any real suggestions.
Albert Wen-Jie Feng 2-Oct-11 7:07am    
Hi, but when I don't add the code "a.m_listvalue.addString("Calculative table : "), the dialog can show and there's no problem, but there's no any content in the ListBox.
Chuck O'Toole 2-Oct-11 7:11am    
Did you debug like I suggested in Solution 1? Is the CWnd member of the CListBox object invalid? Did you properly sub-class m_listvalue by listing it in DoDataExchange()? All of this is necessary for you to use the m_listvalue member at all.
The debugger should have shown you the text of the assertion that failed, maybe something like "hWnd == NULL" or whatever. That information is needed to provide help on the specific assertion.

Also, you can break into the assertion code itself and examine the stack to see just where you called a library function that asserted. Then you can enter that routine and see the arguments you used. Again, this will give some clues as to why the library function didn't like your call.

Unfortunately screenshots are not easy to do in these forums so you'll have to type in the information. Once you have done that, I or others can offer more concrete suggestions on fixing the problem.
-------
I see your updated question. When you hit retry to debug, it should have taken you directly to the assert statement where the test being made is clear.

I'm assuming there's a lot more code than you've shown. Structurally, you're T::Myfunc() function instantiated an object of class A, which includes an instantion of the CListBox object. However, as Solution 2 points out, "instantiating" a ClistBox object is not the same as "Creating a visible window that is a ListBox". The object needs to be "connected" to the actual Windows object that is on the screen. Until that is the case, you cannot do any manipulation on the object. You can check this by using the debugger to examine the content of the 'm_listvalue' object and look at the inner 'CWnd' object. If it is not initialized, then your object has not been connected to the real visible control and this will give you these problems.

This connection between local object instantiation and the real Windows Control is called sub-classing and is something you have to set up in your application before you can manipulate controls in this manner.

Without seeing more of the code and/or how you defined and instantiated the CDialog that is visible, there's not many suggestions on how to fix it.
-------
Ah, your control is not "subclassed" properly. Here's how you do that:

First, as mentioned in the other solution, you cannot reference m_listbox to manipulate the control until *after* the OnInitDialog() member of your Dialog class has been called. It is not until then that the actual screen GUI elements are created.

Second, you need to declare that you are doing Data Exchange and list the controls that you will be subclassing in the DDX list, as below:

C#
class MyDialogClass : public CDialog
{
	virtual void DoDataExchange(CDataExchange* pDX); // declare that you are overriding the DDX routine 
}
void MyDialogClass::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_xxxxxx, m_listbox);
}


Where IDC_xxxxxx is the identifier of the actual Windows Control created in your Dialog Editor
 
Share this answer
 
v3
Comments
Albert Wen-Jie Feng 2-Oct-11 6:56am    
Thank you.
As you said the 'CWnd' is null, and the instantiated isn't null at stack, but the 'm_listvalue' variable as the element of the dialog is null.I've find it. but don't know how to deal with it.
What can I do?
Thank you!!
To clean up the thread, I'm making this a new solution.

Here's the problem. When you do this:
OutputDialog outputDialog;
All that does is create an instance of the object, it does *NOT* create the window itself nor any of the control contained in the window. In other words, no initialization or creation of the controls has occurred yet, especially for IDC_List1.

You cannot use the
C#
outputDialog.m_ListValue.AddString("Calculative table :");
statement yet, while m_ListValue, the object, exists, the backing control (IDC_List1) does not so AddString() has no place to operate on. -->Boom.

The window itself does not exist *until* you issue
C#
outputDialog.DoModal();
. Once you issue that call, you will hit the breakpoints in DoDataExchange() and in OnInitDialog(). Only then can you touch m_ListValue to manipulate the control.

Same applies to
SQL
outputDialog.UpdateData(false);
, it is in the wrong place to call UpdateData().

And, since DoModal() does not return to your code until the dialog box exits, you cannot do any of those functions in that module. The most common place to initialize values in a control is during the OnInitDialog() function. You will have to move your logic there.
 
Share this answer
 
Comments
Albert Wen-Jie Feng 2-Oct-11 22:31pm    
Thank you very much. I've made it clear by debuging the program, as you said it don't exist before adding item to the listbox. but it still cann't work when I exchange the order of DoModal and AddString method, and I still don't know how to organize the structure. At the same time if I add the instantiation process to the OnInitDialog() function, it seems can break the program logic, what I want is just that I can update the data in the listbox and show it by the dialog, then I can do other work. Do you have any other sugestion? thank you!
Chuck O'Toole 3-Oct-11 2:21am    
I'm not sure I understand your response. Did you just move the location of the "AddString" call to *after* the DoModal() in the ShowTableContend() routine? If that's what you did, it cannot work as "DoModal()" function *BLOCKS* until the window exits, That is, DoModal() does *both* create the window *and* wait for the window to be destroyed. As Solution 2 pointed out and showed with a code example, you *must* move your logic file filling the ListBox to *inside* the OnInitDialog() function..
Albert Wen-Jie Feng 3-Oct-11 3:24am    
Oh, yes, When I move the part of adding data to the OnInitDialog() function, the programm can work constrainedly, but this is not the result I want, which means I have to add some unrelative parts to the Dialog class. Is there a better solution? thank you!
Chuck O'Toole 3-Oct-11 9:39am    
Well, if you want to architecturally separate these tasks, you already violated that separation by manipulating the windows control and data member from outside the class that owns it. What I would do is to "give the data" to the OutputData Class during initialization, that is, create a function inside the class that will take the data to be displayed and save it inside the class until the OnInitDialog is called. In other words, create an interface where the main code, having instantiated the class, calls member functions to provide the class with the data to be displayed. Then let the class determine when it is time to display it.
Chuck O'Toole 3-Oct-11 9:41am    
Just to be clear, what do you mean by 'unrelated parts to the Dialog class'? A dialog class (in the Windows sense) exists to manage the display of information and interact with the user. It would seem that filling up the control is totally related to the Dialog class.
Hello

Well, I guess I understand you problem and, if I'm right, then here is the way I did something similar but in a very different way. I do not use the CListBox as the storage control. Instead I simply use a CString array (whatever the way you build and populate the array) and I pass the pointer to that array to the CDialog. The CDialog then fills up the CListBox on OnInitDialog.

Thierry
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900