Page 1 of 1

error: failed in AddChild(): AddChild() called twice

Posted: Tue Dec 17, 2019 10:43 pm
by marco_84
Hello to all
I still need your help!
In the program that I make to keep gas and H2O consumption under control, I have a problem entering two dialogues, namely: "list of readings not sent", in italian language:"lista delle letture non inviate"

and "information on reading" in italian language: "informazioni sulla lettura", the first time I call them everything goes smoothly, but, I call this second time them a wxdebug dialog box that writes:

Code: Select all

./src/common/wincmn.cpp(1336): assert "!GetChildren().Find((wxWindow*)child)" failed in AddChild(): AddChild() called twice
pressing continue I get this error:

Code: Select all

./src/msw/window.cpp(1298): assert "!m_oldWndProc" failed in SubclassWin(): subclassing window twice?
this, stop my program! I forced to close it and restart

I don't know how to solve this problem,

on follow I post the first function: "list of readings not sent:"

Code: Select all

void progletture2 :: OnNonInviate (wxCommandEvent & event)
{
dlgnoninviate = Noninviate.Create(this, wxID_ANY, 
    wxT("Lista delle letture non inviate"), 
wxDefaultPosition, wxSize(400, 400)); 

Noninviate.nnoninviate = 0;
nulettura = elenco_letture->GetFirstItem();
while (nulettura)
{
nucontatore = elenco_letture->GetItemParent(nulettura);
if (nucontatore != elenco_letture->GetRootItem())
{
datiletcontatore = elenco_letture->GetItemText(nucontatore, COL_DATA);
datiletdatacomp = elenco_letture->GetItemText(nulettura, COL_DATA);
}
if (elenco_letture->GetItemText(nulettura, COL_INVIATO) == "No")
{
Noninviate.SetContatore (datiletcontatore);
Noninviate.SetDataLettura(datiletdatacomp);
Noninviate.SetNumLettura(elenco_letture->GetItemText(nulettura, COL_LETTURA));
Noninviate.init();
}
nulettura = elenco_letture->GetNextItem(nulettura);
}

  dlgnoninviate->Connect(ID_ninvlist, wxEVT_TREELIST_ITEM_ACTIVATED, 
      wxCommandEventHandler(noninviate :: OnActivate));

if (dlgnoninviate->Show(TRUE) == wxID_OK)
dlgnoninviate->Destroy();
}
on follow post two function:"information on reading"

Code: Select all

void noninviate :: OnActivate (wxCommandEvent & event)
{
int fatto = 0;
noninviateselected = lista_letture->GetSelection();
nulettura = elenco_letture->GetFirstItem();
while (nulettura)
{
if (lista_letture->GetItemText(noninviateselected, COL_CONTATORE) == elenco_letture->GetItemText(nulettura, COL_CONTATORE))
{
ShowInfo.SetInfoContatore(elenco_letture->GetItemText(nulettura, COL_CONTATORE));
while (fatto == 0)
{
nulettura = elenco_letture->GetNextItem(nulettura);
if (lista_letture->GetItemText(noninviateselected, COL_DATA_LETTURA) == elenco_letture->GetItemText(nulettura, COL_CONTATORE))
{
ShowInfo.SetInfoDataLettura(elenco_letture->GetItemText(nulettura, COL_CONTATORE));
ShowInfo.SetInfoNumLettura(elenco_letture->GetItemText(nulettura, COL_DATA_LETTURA));
ShowInfo.SetInfoInviato(elenco_letture->GetItemText(nulettura, COL_NUM_LETTURA));
fatto = 1;
}
}
}
nulettura = elenco_letture->GetNextItem(nulettura);
}

dlgshowinfo = ShowInfo.Create(this, wxID_ANY, 
"informazioni sulla lettura", 
wxDefaultPosition, wxSize(650, 350));

if (dlgshowinfo->Show(TRUE)== wxID_OK)
{
dlgshowinfo->Destroy();
}
}
thanks for your help

marco_84

Re: error: failed in AddChild(): AddChild() called twice

Posted: Tue Dec 17, 2019 11:22 pm
by doublemax
It's not 100% clear because the types of some classes are not obvious, but i think the problem lies in these lines:

Code: Select all

dlgnoninviate = Noninviate.Create(this, wxID_ANY, 
    wxT("Lista delle letture non inviate"), 
wxDefaultPosition, wxSize(400, 400)); 

Code: Select all

dlgshowinfo = ShowInfo.Create(this, wxID_ANY, 
"informazioni sulla lettura", 
wxDefaultPosition, wxSize(650, 350));
You can not call Create() on the same object more than once.

Re: error: failed in AddChild(): AddChild() called twice

Posted: Wed Dec 18, 2019 5:49 pm
by marco_84
Hello Doublemax
thanks for your help

Can you help me and give info for correct this error? I can't do it myself, I called destroy to close the function but the error remains

marco_84

Re: error: failed in AddChild(): AddChild() called twice

Posted: Wed Dec 18, 2019 6:00 pm
by doublemax
Show the code for Noninviate and ShowInfo. It looks as if these are classes that return a pointer to a dialog? Without knowing more, that doesn't make any sense to me.

Re: error: failed in AddChild(): AddChild() called twice

Posted: Wed Dec 18, 2019 8:27 pm
by marco_84
Hello Doublemax

Thanks

these are the function files that give error

Re: error: failed in AddChild(): AddChild() called twice

Posted: Wed Dec 18, 2019 8:28 pm
by marco_84
this last file

Re: error: failed in AddChild(): AddChild() called twice

Posted: Thu Dec 19, 2019 2:22 am
by doublemax
Is there a special reason why you created these non-standard Create() methods that return a wxDialog* ? They make the code unnecessary complicated.

Unless you actually need the two-step creation (that's the only situation where the Create() method is used), don't use Create.

Just use a custom constructor for your dialog class and then use it like any other dialog. When using a custom dialog, the code should look like this:

Code: Select all

// create dialog on stack
noninviate dlgnoninviate(this, wxID_ANY, wxT("Lista delle letture non inviate"), wxDefaultPosition, wxSize(400, 400)); 
if( dlgnoninviate.ShowModal() == wxID_OK ) 
{
  // process dialog here
}
// no destruction of dialog needed
These two global instances of the dialogs are really bad. Don't do this.

Code: Select all

noninviate Noninviate;
showinfo ShowInfo;
Create a dialog on the stack when you need it.

Re: error: failed in AddChild(): AddChild() called twice

Posted: Thu Dec 19, 2019 7:08 pm
by marco_84
hello doublemax

I will call the dialog in stack mode
but you raised a problem at me:
These two global instances of the dialogs are really bad. Don't do this.
noninviate Noninviate;
showinfo ShowInfo;
how do I need to pass the treelist data from the other classes to "noninviate"?
verified that "noninviate" is a list of read to gas and h2o consumption that be sent to the managers.
for example in this case:

Code: Select all

Noninviate.nnoninviate = 0;
nulettura = elenco_letture->GetFirstItem();
while (nulettura)
{
nucontatore = elenco_letture->GetItemParent(nulettura);
if (nucontatore != elenco_letture->GetRootItem())
{
datiletcontatore = elenco_letture->GetItemText(nucontatore, COL_DATA);
datiletdatacomp = elenco_letture->GetItemText(nulettura, COL_DATA);
}
if (elenco_letture->GetItemText(nulettura, COL_INVIATO) == "No")
{
Noninviate.SetContatore (datiletcontatore);
Noninviate.SetDataLettura(datiletdatacomp);
Noninviate.SetNumLettura(elenco_letture->GetItemText(nulettura, COL_LETTURA));
Noninviate.init();
}
nulettura = elenco_letture->GetNextItem(nulettura);
}
here following the "Init" function of "noninviate":

Code: Select all

void noninviate :: init()
{
letture_noninviate[nnoninviate] = lista_letture->AppendItem(lista_letture->GetRootItem(), m_contatore);
lista_letture->SetItemText(letture_noninviate[nnoninviate], COL_DATA_LETTURA, m_datalettura);
lista_letture->SetItemText(letture_noninviate[nnoninviate], COL_NUM_LETTURA, m_numlettura);
nnoninviate++;
if (lista_letture->GetFirstItem() != lista_letture->GetRootItem())
lista_letture->Select(lista_letture->GetFirstItem());
}
how do I need pass data from "elenco_letture" of the function "main" to "lista_letture" of "noninviate"?

Code: Select all

wxString datiletcontatore, datiletdatacomp, datiletnumlettura;
wxTreeListItem nulettura, nucontatore;
these above are variables called in the "main" program constructor.

Code: Select all

wxTreeListCtrl * elenco_letture;
this above is called in global mode and so I don't like it!

thank you very much for your help and sorry if I waste your time

..... I solved with accessibility and now I practice



marco_84

Re: error: failed in AddChild(): AddChild() called twice

Posted: Thu Dec 19, 2019 7:32 pm
by doublemax
Sorry, but the italian variable names make it really hard for me to follow the program logic.

Generally, if you have some data that needs to be accessed from multiple locations, there are not many options:
a) You pass a pointer to that data around through all hierarchy levels (which can be cumbersome).
b) a Singleton (Google it if you don't know what it is)
c) in wxWidgets, it's common to put the data into the global wxApp instance, accessible through a getter method

Re: error: failed in AddChild(): AddChild() called twice

Posted: Thu Dec 19, 2019 8:41 pm
by marco_84
I'll let you know how I solved it
sorry but it's just that I use wxwidgets

thanks for the suggestions
I will now do some tests following the book by "Julian Smart and Kevin Hock
with Stefan Csomor" which I found in Italian Language

marco_84

Re: error: failed in AddChild(): AddChild() called twice

Posted: Sat Dec 21, 2019 4:39 pm
by marco_84
Hi Doublemax
Just use a custom constructor for your dialog class and then use it like any other dialog. When using a custom dialog, the code should look like this:

// create dialog on stack
noninviate dlgnoninviate(this, wxID_ANY, wxT("Lista delle letture non inviate"), wxDefaultPosition, wxSize(400, 400));
if( dlgnoninviate.ShowModal() == wxID_OK )
{
// process dialog here
}
// no destruction of dialog needed
I tried to make the constructor of the class "noninviate" in stack mode but I can't do it,
Can you post me an example of a constructor that can be called in stack mode?

I'm also satisfied with a minimal.cpp example


marco_84

Re: error: failed in AddChild(): AddChild() called twice

Posted: Sat Dec 21, 2019 5:38 pm
by doublemax
You don't have to change much. Here are just the first few lines for noninviate.cpp/.h

Code: Select all

class NonInviate : public wxDialog
{
DECLARE_CLASS( noninviate )
public:
  NonInviate( wxWindow* parent,
              wxWindowID id = ID_viewnoninviate,
              const wxString& caption = wxT("Lista delle letture non inviate"),
              const wxPoint& pos = wxDefaultPosition,
              const wxSize& size = wxDefaultSize,
              long style = wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU );

Code: Select all

NonInviate::NonInviate( wxWindow* parent,
                        wxWindowID id,
                        const wxString &caption,
                        const wxPoint &pos,
                        const wxSize &size,
                        long style)
                       , wxDialog(parent, id, caption, pos, size, style )
{
wxStaticText * StaticText = new wxStaticText (this, wxID_STATIC,
wxT ( "Lista delle letture ancora da inviare ai gestori delle utenze"),
wxPoint(10, 20), wxSize(200, 20), wxALIGN_LEFT);
(I changed this without compiling it, so there could be typos)

Re: error: failed in AddChild(): AddChild() called twice

Posted: Mon Mar 02, 2020 6:02 pm
by marco_84
Hi Doublemax sorry if I answer you now but I could not connect

I solved it with your last post

Thanks for your help

marco_84