Привязка переменных к контролам в Wxwidgets

Мне тут вот какая мысля пришла... надо бы рассказать о привязке переменных, а то, контролы, это конечно мега-респект, но когда у вас этих самых контролов заводится больше сотни, то хранить это все добро в виде членов класса, как говорится "не есть харашо", проще уж завести структурку, в которую все введенные значения будут автоматически записываться, благо возможность такая есть....

Источник: "wxWidgets programming" by t_rex

С чего бы начать....
Ага, сначала надо бы упомянуть, что все контролы в wxWidgets, будучи потомками от wxWindow, имеют метод TransferDataFromWindow и TransferDataToWindow, которые, соответственно запихивают значения из этих самых контролов (и/или дочерних) в переменные, и устанавливают значения из переменных. MFC-шный аналог UpdateData(TRUE), UpdateData(FALSE).

Для того, чтобы передача данных автоматически производилась и у дочерних контролов, нужно указывать ExtraStyle = wxWS_EX_VALIDATE_RECURSIVELY

Дальше... вся эта доброта обеспечивается валидаторами... кроме того, эти самые валидаторы можно использовать для проверки введенных значений (смотрим пример).

Соответственно, "каждый охотник желает знать...".... э-э-э, о чем это я.... каждый программер может писАть свои собственные валидаторы (вот например ну не хочется нам чтобы имя пользователя отличалось, допустим, от "Вася Пупкин".... напишем-ка мы валидатор, который любое введенное значение будет автоматически в этого Васю Пупкина преобразовывать.... ну, есть, конечно, и более достойные применения... например для проверки правильности ввода даты или времени... или адреса по формату...)

Ладно... перейдем к примеру... чего он у нас делает...
В примере демонстрируется привязка переменных к контролам.... вылазит формочка, на ней 3 текстовых поля (имя, пароль, ip-адрес) и выпадающий список (группа пользователей)
имя и пароль - текстовые
группа - целочисленное значение (индекс элемента списка)
ip-адрес - более-менее правильный ip-адрес, проверка реализована с помощью рукописного валидатора на регулярных выражениях.

Жмакаем на кнопку "Save Info", появляется MessageBox с выдранными из контролов значениями (замечаем, наша форма не хранит в себе указатели на контролы, а хранит структуру, члены которой bind'ятся к контролам)

Смотрим сырцы:

wxRegExValidator.h
<!--c1-->

CODE
<!--ec1-->
#ifndef _WX_REGEX_VALIDATOR_H
#define _WX_REGEX_VALIDATOR_H

#include "wx\wx.h"
#include "wx\regex.h"

class wxRegExValidator : public wxTextValidator
{
protected:
        wxRegEx m_regEx;
        wxString m_reString;
public:
        wxRegExValidator(wxString regExpString, wxString* valPtr = NULL);
        ~wxRegExValidator(void);
        wxObject* Clone() const;
        virtual bool TransferToWindow();
        virtual bool TransferFromWindow(void);
};

#endif
<!--c2-->
<!--ec2-->

wxRegExValidator.cpp
<!--c1-->
CODE
<!--ec1-->
#include "wxRegExValidator.h"

wxRegExValidator::wxRegExValidator(wxString regExpString, wxString* valPtr) : m_regEx(regExpString)
{
    m_stringValue = valPtr;
    m_reString = regExpString;
}

wxRegExValidator::~wxRegExValidator(void) {}

wxObject* wxRegExValidator::Clone() const
{
    return new wxRegExValidator(m_reString, m_stringValue);
}

bool wxRegExValidator::TransferToWindow()
{
    if (m_stringValue == NULL)
        return true;

    if (m_regEx.Matches(*m_stringValue))
    {
        return wxTextValidator::TransferToWindow();
    }

    return false;
}

bool wxRegExValidator::TransferFromWindow(void)
{
    wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow;
    wxString tempString = control->GetValue();

    if (m_regEx.Matches(tempString))
    {
        return wxTextValidator::TransferFromWindow();
    }

    return false;
}
<!--c2-->
<!--ec2-->

Application.cpp
<!--c1-->
CODE
<!--ec1-->
#include <wx/wx.h>
#include <wx/valgen.h>
#include "wxRegExValidator.h"

struct UserInfo
{
    wxString m_UserName;
    wxString m_Password;
    wxString m_IPAddress;
    int m_AccountType;
};

class MyFrame : public wxFrame
{        
    UserInfo m_UserInfo;
public:
    MyFrame(wxWindow * parent);    
    DECLARE_EVENT_TABLE()    
    void OnExit(wxCommandEvent & event);
    void OnSaveInfo(wxCommandEvent & event);
};

enum
{
    ID_USER_TEXT_CTRL,
    ID_USER_PASSWORD,
    ID_ACCOUNT_TYPES_CHOICE,
    ID_IP_ADDRESS_TEXT_CTRL,
    ID_SAVEINFO,

    //------
    ID_UNUSED
};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
EVT_BUTTON(wxID_EXIT, MyFrame::OnExit)
EVT_BUTTON(ID_SAVEINFO, MyFrame::OnSaveInfo)
END_EVENT_TABLE()

MyFrame::MyFrame(wxWindow * parent)
: wxFrame(parent, -1, _("Test"), wxDefaultPosition, wxDefaultSize,
          wxSYSTEM_MENU | wxCLOSE_BOX | wxCAPTION | wxTHICK_FRAME)
{        
    // Позволить обмен данными во всех дочерних окнах при вызове TransferData(From/To)Window
    SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
    SetMinSize(GetSize());
    wxMenuBar * menuBar = new wxMenuBar();
    SetMenuBar(menuBar);
    wxMenu * fileMenu = new wxMenu();
    fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));
    menuBar->Append(fileMenu, _("File"));
    wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);
    SetSizer(sizer);    

    wxPanel * panel1 = new wxPanel(this, -1, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
    wxBoxSizer * panel1sizer = new wxBoxSizer(wxVERTICAL);
    panel1->SetSizer(panel1sizer);
    wxBoxSizer * horsizer1 = new wxBoxSizer(wxHORIZONTAL);
    wxStaticText * userlabel = new wxStaticText(panel1, wxID_ANY, _("User: "), wxDefaultPosition, wxSize(60, -1));
    wxTextCtrl * usertextctrl = new wxTextCtrl(panel1, ID_USER_TEXT_CTRL, _(""));
    /// Привязка переменной m_UserName
    usertextctrl->SetValidator(wxGenericValidator(&m_UserInfo.m_UserName));
    horsizer1->Add(userlabel, 0, wxRIGHT, 5);
    horsizer1->Add(usertextctrl, 1, wxGROW);
    panel1sizer->Add(horsizer1, 0, wxGROW|wxALL, 5);

    wxBoxSizer * horsizer2 = new wxBoxSizer(wxHORIZONTAL);
    wxStaticText * passwordlabel = new wxStaticText(panel1, wxID_ANY, _("Password: "), wxDefaultPosition, wxSize(60, -1));
    wxTextCtrl * passwordtextctrl = new wxTextCtrl(panel1, ID_USER_TEXT_CTRL, _(""),
        wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD);
    /// Привязка переменной m_Password
    passwordtextctrl->SetValidator(wxGenericValidator(&m_UserInfo.m_Password));
    horsizer2->Add(passwordlabel, 0, wxRIGHT, 5);
    horsizer2->Add(passwordtextctrl, 1, wxGROW);
    panel1sizer->Add(horsizer2, 0, wxGROW|wxLEFT|wxRIGHT|wxBOTTOM, 5);

    wxBoxSizer * horsizer3 = new wxBoxSizer(wxHORIZONTAL);
    wxStaticText * accounttypelabel = new wxStaticText(panel1, wxID_ANY, _("Password: "), wxDefaultPosition, wxSize(60, -1));
    wxString account_types[] = {wxString(_("Free")), wxString(_("Professional")), wxString(_("Premium"))};    
    wxChoice * accounttypechoice = new wxChoice(panel1, ID_ACCOUNT_TYPES_CHOICE, wxDefaultPosition, wxDefaultSize, 3, account_types);
    /// Привязка переменной m_AccountType
    accounttypechoice->SetValidator(wxGenericValidator(&m_UserInfo.m_AccountType));
    horsizer3->Add(accounttypelabel, 0, wxRIGHT, 5);
    horsizer3->Add(accounttypechoice, 1, wxGROW);
    panel1sizer->Add(horsizer3, 0, wxGROW|wxLEFT|wxRIGHT|wxBOTTOM, 5);

    wxBoxSizer * horsizer4 = new wxBoxSizer(wxHORIZONTAL);
    wxStaticText * ipaddresslabel = new wxStaticText(panel1, wxID_ANY, _("IP Address: "), wxDefaultPosition, wxSize(60, -1));
    wxTextCtrl * ipaddresstextctrl = new wxTextCtrl(panel1, ID_IP_ADDRESS_TEXT_CTRL, _(""));    
    /// Привязка переменной m_IPAddress с помощью RegEx-валидатора (проверка адреса с помощью регулярных выражений)
    ipaddresstextctrl->SetValidator(wxRegExValidator(wxT("[0-9]{1,3}(.[0-9]{1,3}){3,3}"), &m_UserInfo.m_IPAddress));
    horsizer4->Add(ipaddresslabel, 0, wxRIGHT, 5);
    horsizer4->Add(ipaddresstextctrl, 1, wxGROW);
    panel1sizer->Add(horsizer4, 0, wxGROW|wxALL, 5);

    wxPanel * panel2 = new wxPanel(this, -1, wxDefaultPosition, wxSize(400, 50), wxSUNKEN_BORDER);
    wxBoxSizer * panelsizer = new wxBoxSizer(wxVERTICAL);
    panel2->SetSizer(panelsizer);
    wxBoxSizer * buttonsizer = new wxBoxSizer(wxHORIZONTAL);
    wxButton * btn1 = new wxButton(panel2, ID_SAVEINFO, _("Save Info"));
    wxButton * btn2 = new wxButton(panel2, wxID_EXIT, _("Exit"));
    buttonsizer->Add(btn1, 0, wxALL, 3);
    buttonsizer->Add(btn2, 0, wxALL, 3);

    panelsizer->Add(buttonsizer, 0, wxALIGN_CENTER);
    sizer->Add(panel1, 1, wxEXPAND);
    sizer->Add(panel2, 0, wxGROW);

    CreateStatusBar();        
    Centre();
}

void MyFrame::OnSaveInfo(wxCommandEvent & event)
{
    TransferDataFromWindow();
    wxString res = wxString::Format(_("UserName: %s\r\nPassword: %s\r\nAccoutType: %i\r\nIP Address: %s"),
        m_UserInfo.m_UserName, m_UserInfo.m_Password, m_UserInfo.m_AccountType, m_UserInfo.m_IPAddress);
    wxMessageBox(res);    
}

void MyFrame::OnExit(wxCommandEvent & event)
{
    Close();
}

class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    MyFrame * frame = new MyFrame(NULL);    
    frame->Show();    
    SetTopWindow(frame);
    return true;
}
<!--c2-->


Опубликовал admin
20 Дек, Вторник 2005г.



Программирование для чайников.