Page 1 of 1

Delete an item from wxListCtrl.

Posted: Sat Sep 15, 2018 1:15 pm
by dkaip
Hello in code bellow i am trying to delete items from wxListCtrl, but i take an error on OnSelectItem, last line.
The pos i of item is ok.
../include/wx/dynarray.h(838): assert "uiIndex < m_nCount" failed in Item().
Thank you
Jim.

Code: Select all

TextDrop::TextDrop(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(900, 600))
{

    wxSplitterWindow *spl1 = new wxSplitterWindow(this, -1);
    wxSplitterWindow *spl2 = new wxSplitterWindow(spl1, -1);
    m_gdir = new wxGenericDirCtrl(spl1, -1, wxT("/home/"),wxPoint(-1, -1), wxSize(50, 50), wxDIRCTRL_DIR_ONLY);

    m_lc1 = new wxListCtrl(spl2, -1, wxPoint(50, 50),wxSize(50, 50), wxLC_LIST);
    m_lc2 = new wxListCtrl(spl2, -1, wxPoint(50, 50),wxSize(50, 50), wxLC_LIST);

    MyTextDropTarget *mdt = new MyTextDropTarget(m_lc2);
    m_lc2->SetDropTarget(mdt);

    Connect(m_lc1->GetId(), wxEVT_COMMAND_LIST_BEGIN_DRAG,wxListEventHandler(TextDrop::OnDragInit));

    wxTreeCtrl *tree = m_gdir->GetTreeCtrl();

    spl2->SplitHorizontally(m_lc1, m_lc2);
    spl1->SplitVertically(m_gdir, spl2);

    Connect(tree->GetId(), wxEVT_COMMAND_TREE_SEL_CHANGED,wxCommandEventHandler(TextDrop::OnSelect));
    Connect(m_lc2->GetId(), wxEVT_COMMAND_LIST_ITEM_SELECTED,wxListEventHandler(TextDrop::OnSelectItem));

    Center();
}
MyTextDropTarget::MyTextDropTarget(wxListCtrl *owner)
{
    m_owner = owner;
}

bool MyTextDropTarget::OnDropText(wxCoord x, wxCoord y,const wxString& data)
{
    m_owner->InsertItem(0, data);
    return true;
}

void TextDrop::OnSelectItem(wxListEvent& event)
{
    wxListItem it=event.GetItem();
    long i=it.GetId();
//    m_lc2->DeleteItem(i);
    m_lc2->DeleteAllItems();
}

Re: Delete an item from wxListCtrl.

Posted: Sat Sep 15, 2018 5:56 pm
by doublemax
I assume the line that causes the problem is:

Code: Select all

m_lc2->DeleteItem(i);
and not the other one?

The assert message is clear: The item index is bigger too big and exceeds last item in the control. Check the values of "i" and "m_lc2->GetItemCount".

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 4:31 am
by dkaip
Yes this is line with problem.
I assume the line that causes the problem is:
m_lc2->DeleteItem(i);
Supposse m_lc2 has 2 objects, and click to first i take i=0 and j=2.
But i<j and proplem is the same.
Is problem of library? I use wxWidgets3.0.3 stable.
Even using DeleteAllItems () i have the same problem, so must be in library?
Thank you
Jim

Code: Select all

    wxListItem it=event.GetItem();
    long i=it.GetId();
    int j=m_lc2->GetItemCount();
    m_lc2->DeleteItem(i);

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 8:10 am
by doublemax
Even using DeleteAllItems () i have the same problem, so must be in library?
Very unlikely, there must be something elso going on.

Please try to create a minimal, compilable sample that shows the problem.

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 10:34 am
by PB
Using the simple code below it basically (did not test how multiple selection works) seems to work as expected( git master, MSW)

Code: Select all

#include <wx/wx.h>
#include <wx/listctrl.h>

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(600, 400))
    {                               
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);        

        m_listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_LIST);        
        for ( int i = 0; i < 20; ++i )
            m_listCtrl->InsertItem(m_listCtrl->GetItemCount(), wxString::Format("Item %d", i));            
        m_listCtrl->Bind(wxEVT_COMMAND_LIST_ITEM_SELECTED, &MyFrame::OnItemSelected, this);
        mainSizer->Add(m_listCtrl, wxSizerFlags().Expand().Proportion(3).Border(wxALL, 10));

         wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, 
            wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);        
        mainSizer->Add(logCtrl, wxSizerFlags().Expand().Proportion(1).Border(wxALL, 10));
        wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));      
                            
        SetSizer(mainSizer);         
    }	
private:
    wxListCtrl* m_listCtrl;

    void OnItemSelected(wxListEvent& evt)
    {        
        const long itemId = evt.GetItem().GetId();        

        wxASSERT(itemId == evt.GetIndex());
        
        wxLogMessage("OnItemSelected(): itemId = %ld, item count = %ld", 
            itemId, m_listCtrl->GetItemCount());

        m_listCtrl->DeleteItem(itemId);
    }
};

class MyApp : public wxApp
{
public:	
	bool OnInit()
	{
        (new MyFrame)->Show();
        return true;
	}
}; wxIMPLEMENT_APP(MyApp);

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 11:21 am
by dkaip
Hello.
I upload the code, is from zetcode example.
Thank you
Jim

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 11:27 am
by dkaip
For PB code i take error when pick an item...
Is library's bug?
/usr/include/wx-3.0/wx/strvararg.h(456): assert "(argtype & (wxFormatStringSpecifier<T>::value)) == argtype" failed in wxArgNormalizer(): format specifier doesn't match argument type
But when disable code

Code: Select all

//        wxLogMessage("OnItemSelected(): itemId = %ld, item count = %ld",
//            itemId, m_listCtrl->GetItemCount());
on item click item delete. But when click on last item i take error ...
../include/wx/dynarray.h(838): assert "uiIndex < m_nCount" failed in Item().
No drag and drop operation happens.
Thank you
Jim

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 12:49 pm
by doublemax
I upload the code, is from zetcode example.
Under Windows i don't see any crash with your code. I can't test under Linux.

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 1:24 pm
by PB
dkaip wrote:For PB code i take error when pick an item...
Is library's bug?
/usr/include/wx-3.0/wx/strvararg.h(456): assert "(argtype & (wxFormatStringSpecifier<T>::value)) == argtype" failed in wxArgNormalizer(): format specifier doesn't match argument type
But when disable code

Code: Select all

//        wxLogMessage("OnItemSelected(): itemId = %ld, item count = %ld",
//            itemId, m_listCtrl->GetItemCount());
This may be because GetItemCount() returns int and therefore the second printf specifier should be "%d" and not "%ld" (on my platform there is not difference between int and long). But as you said, this has no relation to the issue in question...

Re: Delete an item from wxListCtrl.

Posted: Sun Sep 16, 2018 9:38 pm
by dkaip
In Linux wxWidgets lib must have problem.
It must works on both OS.
Thank you
Jim.

Re: Delete an item from wxListCtrl.

Posted: Mon Sep 17, 2018 5:39 am
by PB
While it does not seem very likely, perhaps deleting the item in the OnSelect event handler may be an issue. Try doing it with CallAfter instead, e.g. like this

Code: Select all

#include <wx/wx.h>
#include <wx/listctrl.h>

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(600, 400))
    {                               
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);       

        m_listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_LIST);       
        for ( int i = 0; i < 5; ++i )
            m_listCtrl->InsertItem(m_listCtrl->GetItemCount(), wxString::Format("Item %d", i));           
        m_listCtrl->Bind(wxEVT_COMMAND_LIST_ITEM_SELECTED, &MyFrame::OnItemSelected, this);
        mainSizer->Add(m_listCtrl, wxSizerFlags().Expand().Proportion(3).Border(wxALL, 10));

         wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
            wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);       
        mainSizer->Add(logCtrl, wxSizerFlags().Expand().Proportion(1).Border(wxALL, 10));
        wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));     
                           
        SetSizer(mainSizer);         
    }   
private:
    wxListCtrl* m_listCtrl;

    void DeleteListCtrlItem(long item)
    {
        wxLogMessage("DeleteListCtrlItem(): item = %ld, item count = %d", item, m_listCtrl->GetItemCount());
        m_listCtrl->DeleteItem(item);
    }

    void OnItemSelected(wxListEvent& evt)
    {       
        const long itemId = evt.GetItem().GetId();       

        wxASSERT(itemId == evt.GetIndex());
       
        wxLogMessage("OnItemSelected(): itemId = %ld, item count = %d", itemId, m_listCtrl->GetItemCount());
        CallAfter(&MyFrame::DeleteListCtrlItem, itemId);
    }
};

class MyApp : public wxApp
{
public:   
   bool OnInit()
   {
        (new MyFrame)->Show();
        return true;
   }
}; wxIMPLEMENT_APP(MyApp);