代码之家  ›  专栏  ›  技术社区  ›  NeomerArcana

WxtExtValidator导致崩溃

  •  0
  • NeomerArcana  · 技术社区  · 6 年前

    我有一个对话框窗口,里面有一些动态控件。基本上,在构造时,我向它传递一个指向结构的指针,在这个结构中是 std::pair<wxString,wxString> . 对于其中的每一个,我需要创建另一行,其中包含三个控件,一个 wxTextCtrl , wxChoice 和A wxButton .

    这部分工作,基于容器中的可用项,我在对话框构造时成功地创建了这些项。我也用 wxTextValidator 连接 WXTEXTCRL 有了第一个 wxString 一对一。如果集装箱里有三对,我就有三对 WXTEXTCRL 创建了,每个都有一个验证器 WxStk .

    wxID_OK 在对话框中,文本验证器工作,而我的原始结构(我作为指针传递给它)包含正确的数据。

    但是,我也在对话框中添加了一个按钮,它应该允许创建新的 STD::配对和lt;WxStand,WxStand & Gt; 容器中的记录。如果我这样做 WXIDIDOK ,应用程序崩溃。Drmingw使指向 WxStk 无效,但这是不可能的,因为单击按钮时我正在容器中创建新记录,并指向 WxtExtValidator验证程序 到这个新创建的记录。它存储在对话框之外,因此在关闭对话框时不会失效。

    我的数据结构:

    struct StoryNodeData
    {
        wxString title;
        wxString text;
        std::vector<std::pair<wxString,wxString>> options;
    };
    

    我的对话框标题:

    #ifndef STORYDIALOG_H
    #define STORYDIALOG_H
    
    #include "flowchart.hpp"
    
    #include <map>
    
    //(*Headers(StoryDialog)
    #include <wx/bmpbuttn.h>
    #include <wx/button.h>
    #include <wx/choice.h>
    #include <wx/dialog.h>
    #include <wx/gbsizer.h>
    #include <wx/scrolwin.h>
    #include <wx/sizer.h>
    #include <wx/textctrl.h>
    //*)
    
    class StoryDialog: public wxDialog
    {
        public:
    
            StoryDialog(wxWindow* parent,StoryNodeData* data, wxArrayString titles,wxWindowID id=wxID_ANY,const wxPoint& pos=wxDefaultPosition,const wxSize& size=wxDefaultSize);
            virtual ~StoryDialog();
    
            void HandleOptionDelete(wxCommandEvent& e);
    
            //(*Declarations(StoryDialog)
            wxButton* OptionButton;
            wxFlexGridSizer* OptionsSizer;
            wxScrolledWindow* OptionsWindow;
            wxTextCtrl* EventTextCtrl;
            wxTextCtrl* TitleTextCtrl;
            //*)
    
        protected:
    
            //(*Identifiers(StoryDialog)
            static const long ID_TEXTCTRL1;
            static const long ID_TEXTCTRL2;
            static const long ID_BUTTON1;
            static const long ID_TEXTCTRL3;
            static const long ID_CHOICE1;
            static const long ID_BITMAPBUTTON1;
            static const long ID_SCROLLEDWINDOW1;
            //*)
    
        private:
    
            //(*Handlers(StoryDialog)
            void OnNewOptionButtonClick(wxCommandEvent& event);
            void OnBitmapButton1Click(wxCommandEvent& event);
            //*)
    
            std::map<wxObject*,std::tuple<wxTextCtrl*, wxChoice*, std::size_t>> m_optionCtrls;
            StoryNodeData* m_data;
            wxArrayString m_titles;
    
            void ConstructOption(wxString* text, wxString* title);
    
            DECLARE_EVENT_TABLE()
    };
    
    #endif
    

    以及对话实现:

    #include "StoryDialog.h"
    
    #include <wx/artprov.h>
    #include <wx/valgen.h>
    
    //(*InternalHeaders(StoryDialog)
    
    #include <wx/artprov.h>
    
    #include <wx/bitmap.h>
    
    #include <wx/image.h>
    
    #include <wx/intl.h>
    
    #include <wx/string.h>
    
    //*)
    
    //(*IdInit(StoryDialog)
    
    const long StoryDialog::ID_TEXTCTRL1 = wxNewId();
    
    const long StoryDialog::ID_TEXTCTRL2 = wxNewId();
    
    const long StoryDialog::ID_BUTTON1 = wxNewId();
    
    const long StoryDialog::ID_TEXTCTRL3 = wxNewId();
    
    const long StoryDialog::ID_CHOICE1 = wxNewId();
    
    const long StoryDialog::ID_BITMAPBUTTON1 = wxNewId();
    
    const long StoryDialog::ID_SCROLLEDWINDOW1 = wxNewId();
    
    //*)
    
    BEGIN_EVENT_TABLE(StoryDialog,wxDialog)
        //(*EventTable(StoryDialog)
        //*)
    END_EVENT_TABLE()
    
    StoryDialog::StoryDialog(wxWindow* parent,StoryNodeData* data, wxArrayString titles,wxWindowID id,const wxPoint& pos,const wxSize& size)
    {
        //(*Initialize(StoryDialog)
    
        wxBitmapButton* BitmapButton1;
    
        wxChoice* Choice1;
    
        wxFlexGridSizer* FlexGridSizer1;
    
        wxGridBagSizer* GridBagSizer1;
    
        wxStaticBoxSizer* StaticBoxSizer1;
    
        wxStdDialogButtonSizer* StdDialogButtonSizer1;
    
        wxTextCtrl* TextCtrl1;
    
    
        Create(parent, wxID_ANY, _("New Event"), wxDefaultPosition, wxDefaultSize, wxSTAY_ON_TOP|wxCAPTION|wxRESIZE_BORDER|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxSIMPLE_BORDER, _T("wxID_ANY"));
    
        GridBagSizer1 = new wxGridBagSizer(0, 0);
    
        GridBagSizer1->AddGrowableCol(0);
    
        GridBagSizer1->AddGrowableRow(1);
    
        TitleTextCtrl = new wxTextCtrl(this, ID_TEXTCTRL1, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxTextValidator(wxFILTER_NONE,&data->title), _T("ID_TEXTCTRL1"));
    
        GridBagSizer1->Add(TitleTextCtrl, wxGBPosition(0, 0), wxDefaultSpan, wxALL|wxEXPAND, 5);
    
        EventTextCtrl = new wxTextCtrl(this, ID_TEXTCTRL2, wxEmptyString, wxDefaultPosition, wxSize(259,138), wxTE_MULTILINE|wxVSCROLL, wxTextValidator(wxFILTER_NONE,&data->text), _T("ID_TEXTCTRL2"));
    
        GridBagSizer1->Add(EventTextCtrl, wxGBPosition(1, 0), wxDefaultSpan, wxALL|wxEXPAND, 5);
    
        StdDialogButtonSizer1 = new wxStdDialogButtonSizer();
    
        StdDialogButtonSizer1->AddButton(new wxButton(this, wxID_OK, wxEmptyString));
    
        StdDialogButtonSizer1->AddButton(new wxButton(this, wxID_CANCEL, wxEmptyString));
    
        StdDialogButtonSizer1->Realize();
    
        GridBagSizer1->Add(StdDialogButtonSizer1, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
    
        StaticBoxSizer1 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Options"));
    
        FlexGridSizer1 = new wxFlexGridSizer(2, 1, 0, 0);
    
        FlexGridSizer1->AddGrowableCol(0);
    
        FlexGridSizer1->AddGrowableRow(1);
    
        OptionButton = new wxButton(this, ID_BUTTON1, _("New Option"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
    
        FlexGridSizer1->Add(OptionButton, 1, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
    
        OptionsWindow = new wxScrolledWindow(this, ID_SCROLLEDWINDOW1, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER|wxVSCROLL, _T("ID_SCROLLEDWINDOW1"));
    
        OptionsSizer = new wxFlexGridSizer(0, 3, 0, 0);
    
        OptionsSizer->AddGrowableCol(0);
    
        TextCtrl1 = new wxTextCtrl(OptionsWindow, ID_TEXTCTRL3, _("Text"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_TEXTCTRL3"));
    
        OptionsSizer->Add(TextCtrl1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    
        Choice1 = new wxChoice(OptionsWindow, ID_CHOICE1, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CHOICE1"));
    
        OptionsSizer->Add(Choice1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    
        BitmapButton1 = new wxBitmapButton(OptionsWindow, ID_BITMAPBUTTON1, wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_DELETE")),wxART_BUTTON), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, _T("ID_BITMAPBUTTON1"));
    
        OptionsSizer->Add(BitmapButton1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    
        OptionsWindow->SetSizer(OptionsSizer);
    
        OptionsSizer->Fit(OptionsWindow);
    
        OptionsSizer->SetSizeHints(OptionsWindow);
    
        FlexGridSizer1->Add(OptionsWindow, 1, wxALL|wxEXPAND, 5);
    
        StaticBoxSizer1->Add(FlexGridSizer1, 1, wxEXPAND, 5);
    
        GridBagSizer1->Add(StaticBoxSizer1, wxGBPosition(0, 1), wxGBSpan(2, 1), wxALL|wxEXPAND, 5);
    
        SetSizer(GridBagSizer1);
    
        GridBagSizer1->Fit(this);
    
        GridBagSizer1->SetSizeHints(this);
    
    
        Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&StoryDialog::OnNewOptionButtonClick);
    
        //*)
    
    
        OptionsWindow->SetScrollRate(5,5);
    
        OptionsWindow->DestroyChildren();
    
        Bind(wxEVT_BUTTON, &StoryDialog::HandleOptionDelete, this);
    
        m_data = data;
        m_titles = titles;
    
        // construct the existing options
        for(auto itr = m_data->options.begin(); itr != m_data->options.end(); ++itr)
        {
            auto title = &((*itr).first);
            auto text = &((*itr).second);
    
            ConstructOption(text,title);
        }
    }
    
    StoryDialog::~StoryDialog()
    {
        //(*Destroy(StoryDialog)
        //*)
    }
    
    
    void StoryDialog::HandleOptionDelete(wxCommandEvent& e)
    {
        auto b = e.GetEventObject();
        auto itr = m_optionCtrls.find(b);
        if(m_optionCtrls.end() != itr)
        {
            auto button = itr->first;
            auto pa = itr->second;
            m_optionCtrls.erase(itr);
    
            OptionsSizer->Detach(std::get<0>(pa));
            OptionsSizer->Detach(std::get<1>(pa));
            OptionsSizer->Detach(reinterpret_cast<wxBitmapButton*>(button));
    
            std::get<0>(pa)->Destroy();
            std::get<1>(pa)->Destroy();
            reinterpret_cast<wxBitmapButton*>(button)->Destroy();
    
            auto index = std::get<2>(pa);
            auto itr = m_data->options.begin() + index;
            m_data->options.erase(itr);
        }
    
        OptionsSizer->Layout();
        OptionsWindow->SetSizer(OptionsSizer);
        SendSizeEvent();
    
        e.Skip(true);
    }
    
    void StoryDialog::OnNewOptionButtonClick(wxCommandEvent& event)
    {
        m_data->options.push_back(std::make_pair("",""));
    
        auto itr = m_data->options.end()-1;
    
        auto text = &((*(itr)).second);
        auto title = &((*(itr)).first);
    
        ConstructOption(text,title);
    }
    
    void StoryDialog::ConstructOption(wxString* text, wxString* title)
    {
        long tId = wxNewId();
        long cId = wxNewId();
        long bId = wxNewId();
    
        auto optionTextCtrl = new wxTextCtrl(OptionsWindow, tId, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxTextValidator(wxFILTER_NONE,text));
    
        OptionsSizer->Add(optionTextCtrl, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    
        auto optionTitleCtrl = new wxChoice(OptionsWindow, cId, wxDefaultPosition, wxDefaultSize, m_titles, 0, wxGenericValidator(title));
    
        OptionsSizer->Add(optionTitleCtrl, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    
        auto deleteButtonCtrl = new wxBitmapButton(OptionsWindow, bId, wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_DELETE")),wxART_BUTTON), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator);
    
        OptionsSizer->Add(deleteButtonCtrl, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    
        OptionsSizer->Layout();
        OptionsWindow->SetSizer(OptionsSizer);
        SendSizeEvent();
    
        m_optionCtrls[deleteButtonCtrl] = std::make_tuple(optionTextCtrl,optionTitleCtrl,m_optionCtrls.size()-1);
    }
    

    您将注意到,无论是基于所提供的数据,还是用户通过控件添加新数据,我创建动态控件的方式都是相同的。唯一的区别是添加新记录时,我首先在容器中创建记录

    1 回复  |  直到 6 年前
        1
  •  2
  •   VZ.    6 年前

    指向元素的指针 std::vector<> 当向量内容更改时(例如,当您向其附加更多元素时),可以(也将)无效,因此您不能这样做。

    相反,您需要使用一个不会移动其值的容器(例如 std::[unordered_]map<> 或存储 unique_ptr<> 在你的向量中。