Работа с Xml в Wxwidgets

Решил тут немного просветить народ по поводу работы с XML в wxWidgets. XML там вроде рудимента работает, он как бы есть, но для него нету официальной документации, к тому же не полностью реализованы все типы элементов, что, однако, совсем не мешает нормально им пользоваться... просто надо захотеть... Еще хотелось бы отметить, что работа с XML реализована посредством юзания библиотечки expat, которая, как бы, полностью входит в дистриб wxWidgets.

Для нормальной работы примера необходимы следующие либы:
Debug: wxmsw26d_core.lib wxbase26d.lib wxbase26d_xml.lib wxexpatd.lib
Release: wxmsw26_core.lib wxbase26.lib wxbase26_xml.lib wxexpat.lib

Что, собственно, наш пример делает... открывается формочка, вверху поля ввода Имя/Отчество/Фамилия. Ниже список записей, еще ниже - кнопочки Добавить/Удалить/Очистить. Еще есть кнопочки Открыть/Сохранить - ясное дело открывает и сохраняет программка наши записи в XML-овский формат... ну и конечно же, еще есть кнопочка ЗАКРЫТЬ... но ею пользоваться надо после того, как пожмакали все остальные.
Приятного юзания. Сырцы смотрим ниже

<!--c1-->

CODE
<!--ec1-->
#include <wx/wx.h>
#include <wx/valgen.h>
#include <wx/filedlg.h>
#include <wx/listctrl.h>
#include <wx/settings.h>
// Этот файл нужен для работы с XML
#include <wx/xml/xml.h>

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

DECLARE_APP(MyApp)
IMPLEMENT_APP(MyApp)

class MyFrame : public wxFrame
{
    // В этом списке будут отобраться наши записи
    wxListCtrl * m_ListCtrl;
    // Буферы для хранения имени, отчества и фамилии
    wxString m_Name;
    wxString m_Surname;
    wxString m_Patronymic;
    // Эта функция загружает записи из файла
    void LoadFromFile(wxString filename);
    // Эта функция сохраняет записи в файл
    void SaveToFile(wxString filename);
    // Эта функция удаляет все записи
    void ClearAll();
public:
    MyFrame(wxWindow * parent);
    DECLARE_EVENT_TABLE()
    /*
    Этот метод включает/выключает кнопку удаления записи в зависимости от
    того, есть ли у нас выделенные записи в списке
    */
    void OnDeleteButtonUpdateUI(wxUpdateUIEvent & event);
    /*
    Этот метод включает/выключает кнопку удаления всех записей в зависимости от
    того, есть ли у нас что-либо в списке
    */
    void OnClearButtonUpdateUI(wxUpdateUIEvent & event);    
    // Обработчик кнопки ОТКРЫТЬ
    void OnOpen(wxCommandEvent & event);
    // Обработчик кнопки СОХРАНИТЬ
    void OnSave(wxCommandEvent & event);
    // Обработчик кнопки ДОБАВИТЬ ЗАПИСЬ
    void OnAddRecord(wxCommandEvent & event);
    // Обработчик кнопки  УДАЛИТЬ ЗАПИСЬ
    void OnDeleteRecord(wxCommandEvent & event);
    // Обработчик кнопки УДАЛИТЬ ВСЁ
    void OnClearAll(wxCommandEvent & event);
    // Обработчик кнопки ВЫХОД
    void OnExit(wxCommandEvent & event);
};

// Идентификаторы контролов
enum
{
    ID_ADD_RECORD = 10001,
    ID_DELETE_RECORD,
    ID_CLEAR_ALL,    
};

// Таблица обработчиков сообщений
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
// Обработчики обновления ГУИ
EVT_UPDATE_UI(ID_DELETE_RECORD, MyFrame::OnDeleteButtonUpdateUI)
EVT_UPDATE_UI(ID_CLEAR_ALL, MyFrame::OnClearButtonUpdateUI)
// Обработчики для кнопок
EVT_BUTTON(wxID_OPEN, MyFrame::OnOpen)
EVT_BUTTON(wxID_SAVE, MyFrame::OnSave)
EVT_BUTTON(ID_ADD_RECORD, MyFrame::OnAddRecord)
EVT_BUTTON(ID_DELETE_RECORD, MyFrame::OnDeleteRecord)
EVT_BUTTON(ID_CLEAR_ALL, MyFrame::OnClearAll)
EVT_BUTTON(wxID_EXIT, MyFrame::OnExit)
END_EVENT_TABLE()

MyFrame::MyFrame(wxWindow * parent)
    :wxFrame(parent, -1, _("Test"), wxDefaultPosition, wxSize(640,480))
{    
    // Устанавливаем минимальный размер формы
    SetMinSize(wxSize(640, 480));
    // Создаем главный сайзер
    wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);
    SetSizer(sizer);        
    // Создаем горизонтальный сайзер для полей ввода параметров
    wxBoxSizer * controls_sizer = new wxBoxSizer(wxHORIZONTAL);
    
    // Создаем текстовое поле ввода имени и лэйбочку к нему
    wxBoxSizer * name_sizer = new wxBoxSizer(wxVERTICAL);
    wxStaticText * name_label = new wxStaticText(this, wxID_ANY, _("Name:"));
    wxTextCtrl * name_text_ctrl = new wxTextCtrl(this, wxNewId(), wxEmptyString,
        wxDefaultPosition, wxSize(100, -1));    
    name_text_ctrl->SetValidator(wxGenericValidator(&m_Name));
    // Помещаем поле ввода имени и лэйбочку в вертикальный сайзер
    name_sizer->Add(name_label, 0, wxBOTTOM, 5);
    name_sizer->Add(name_text_ctrl, 0, wxGROW);

    // Создаем текстовое поле ввода отчества и лэйбочку к нему
    wxBoxSizer * patronymic_sizer = new wxBoxSizer(wxVERTICAL);
    wxStaticText * patronymic_label = new wxStaticText(this, wxID_ANY, _("Patronymic:"));
    wxTextCtrl * patronymic_text_ctrl = new wxTextCtrl(this, wxNewId(), wxEmptyString,
        wxDefaultPosition, wxSize(100, -1));
    patronymic_text_ctrl->SetValidator(wxGenericValidator(&m_Patronymic));
    // Помещаем поле ввода отчества и лэйбочку в вертикальный сайзер
    patronymic_sizer->Add(patronymic_label, 0, wxBOTTOM, 5);
    patronymic_sizer->Add(patronymic_text_ctrl, 0, wxGROW);

    // Создаем текстовое поле ввода фамилии и лэйбочку к нему
    wxBoxSizer * surname_sizer = new wxBoxSizer(wxVERTICAL);
    wxStaticText * surname_label = new wxStaticText(this, wxID_ANY, _("Surame:"));
    wxTextCtrl * surname_text_ctrl = new wxTextCtrl(this, wxNewId(), wxEmptyString,
        wxDefaultPosition, wxSize(100, -1));
    surname_text_ctrl->SetValidator(wxGenericValidator(&m_Surname));
    // Помещаем поле ввода фамилии и лэйбочку в вертикальный сайзер
    surname_sizer->Add(surname_label, 0, wxBOTTOM, 5);
    surname_sizer->Add(surname_text_ctrl, 0, wxGROW);

    // Помещаем наши вертикальные сайзеры с полями ввода в горизонтальный сайзер
    controls_sizer->Add(name_sizer, 1, wxGROW|wxALL, 5);
    controls_sizer->Add(patronymic_sizer, 1, wxGROW|wxALL, 5);
    controls_sizer->Add(surname_sizer, 1, wxGROW|wxALL, 5);

    // Создаем список для отображения записей
    m_ListCtrl = new wxListCtrl(this, wxNewId(), wxDefaultPosition, wxDefaultSize,
        wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_HRULES|wxLC_VRULES);
    // Добавляем новые колонки
    m_ListCtrl->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
    m_ListCtrl->InsertColumn(1, _("Patronymic"), wxLIST_FORMAT_LEFT, 200);
    m_ListCtrl->InsertColumn(2, _("Surname"), wxLIST_FORMAT_LEFT, 200);

    // Создаем сайзер для кнопок
    wxBoxSizer * button_sizer = new wxBoxSizer(wxHORIZONTAL);
    // Создаем кнопки
    wxButton * add_record_button = new wxButton(this, ID_ADD_RECORD, _("Add"));
    wxButton * delete_record_button = new wxButton(this, ID_DELETE_RECORD, _("Delete"));
    wxButton * clear_all_button = new wxButton(this, ID_CLEAR_ALL, _("Clear"));
    wxButton * open_button = new wxButton(this, wxID_OPEN, _("Open"));
    wxButton * save_button = new wxButton(this, wxID_SAVE, _("Save"));
    wxButton * exit_button = new wxButton(this, wxID_EXIT, _("Exit"));    
    // Помещаем кнопки в горизонтальный сайзер
    button_sizer->Add(add_record_button, 0, wxRIGHT, 5);
    button_sizer->Add(delete_record_button, 0, wxRIGHT, 5);    
    button_sizer->Add(clear_all_button, 0, wxRIGHT, 25);
    button_sizer->Add(open_button, 0, wxRIGHT, 5);
    button_sizer->Add(save_button, 0, wxRIGHT, 25);
    button_sizer->Add(exit_button, 0);
    // Помещаем горизонтальный сайзер с кнопками на форму
    sizer->Add(controls_sizer, 0, wxGROW);
    sizer->Add(m_ListCtrl, 1, wxEXPAND|wxALL, 5);
    sizer->Add(button_sizer, 0, wxALIGN_RIGHT|wxLEFT|wxRIGHT|wxBOTTOM, 5);
    
    // Устанавливаем цвет формы в стандартный для системы
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));

    // Создаем строку состояния
    CreateStatusBar(2);
    // Центрируем форму
    Centre();
}

void MyFrame::OnDeleteButtonUpdateUI(wxUpdateUIEvent & event)
{
    // Наша кнопка УДАЛИТЬ ЗАПИСЬ будет активна когда есть выделенные записи
    event.Enable(m_ListCtrl->GetNextItem(-1,
        wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
}

void MyFrame::OnClearButtonUpdateUI(wxUpdateUIEvent & event)
{
    // Кнопка УДАЛИТЬ ВСЁ будет активна когда в списке есть записи
    event.Enable(m_ListCtrl->GetItemCount()>0);
}

void MyFrame::OnOpen(wxCommandEvent & event)
{
    // Создаем диалог выбора файла
    wxFileDialog * dlg = new wxFileDialog(this);
    // Устанавливаем стиль диалога на открытие файла
    dlg->SetStyle(wxOPEN);
    // Устанавливаем фильтр
    dlg->SetWildcard(_("XML-Files (*.xml)|*.xml"));
    // Если выбрали файл....
    if(dlg->ShowModal() == wxID_OK)
    {
        // ... Загрузить записи
        LoadFromFile(dlg->GetPath());
    }
    // Не забываем диалог удалить
    dlg->Destroy();
}

void MyFrame::OnSave(wxCommandEvent & event)
{
    // Создаем диалог выбора файла
    wxFileDialog * dlg = new wxFileDialog(this);
    // Устанавливаем стиль диалога на сохранение файла
    dlg->SetStyle(wxSAVE);
    // Устанавливаем фильтр
    dlg->SetWildcard(_("XML-Files (*.xml)|*.xml"));
    // Если выбрали файл....
    if(dlg->ShowModal() == wxID_OK)
    {
        // ... Сохранить записи
        SaveToFile(dlg->GetPath());
    }
    // Не забываем диалог удалить
    dlg->Destroy();
}

void MyFrame::OnAddRecord(wxCommandEvent & event)
{
    // Получаем данные из контролов в переменные
    TransferDataFromWindow();
    // Добавляем новую запись в список
    long index = m_ListCtrl->InsertItem(m_ListCtrl->GetItemCount(), m_Name);
    // Устанавливаем значение во второй и третьей колонке
    m_ListCtrl->SetItem(index, 1, m_Patronymic);
    m_ListCtrl->SetItem(index, 2, m_Surname);
    // Очищаем переменные
    m_Name = m_Patronymic = m_Surname = wxEmptyString;
    // Обновляем контролы из переменных.. чтобы очистить
    TransferDataToWindow();
    // Обновляем список
    m_ListCtrl->Refresh();
}

void MyFrame::OnDeleteRecord(wxCommandEvent & event)
{
    // Ищем выделенный элемент
    long item = m_ListCtrl->GetNextItem(-1,
         wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
    // Если нашли...
    if(item != -1)
    {
        // ... удаляем
        m_ListCtrl->DeleteItem(item);
    }
}

void MyFrame::OnClearAll(wxCommandEvent & event)
{
    // Вызываем процедурку удаления
    ClearAll();
}

void MyFrame::OnExit(wxCommandEvent & event)
{
    // Закрываем форму
    Close();
}

void MyFrame::ClearAll()
{
    // Удалить все записи и колонки
    m_ListCtrl->ClearAll();        
    // Пересоздаем структуру колонок
    m_ListCtrl->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
    m_ListCtrl->InsertColumn(1, _("Patronymic"), wxLIST_FORMAT_LEFT, 200);
    m_ListCtrl->InsertColumn(2, _("Surname"), wxLIST_FORMAT_LEFT, 200);
}

void MyFrame::LoadFromFile(wxString filename)
{
    // Открываем документ
    wxXmlDocument doc(filename);
    // Если не получилось, то дико ругаемся и выходим
    if(!doc.IsOk())
    {
        wxMessageBox(_("Can't open file !!!"));
        return;
    }
    // Получаем корневой элемент документа
    wxXmlNode * root_node = doc.GetRoot();
    // Получаем указатель на первый дочерний элемент корневого
    wxXmlNode * curnode = root_node->GetChildren();
    wxString tmp_str;
    // Запрещаем обновление списка
    m_ListCtrl->Freeze();
    // очищаем список
    ClearAll();
    long index(0);
    // Проходимся по всем дочерним элементам корневого элемента
    while(curnode)
    {
        // Если это элемент, в котором хранится запись нашей записной книжки...
        if(curnode->GetName() == wxT("NotebookRecord"))
        {
            // Получаем имя
            tmp_str = curnode->GetPropVal(wxT("Name"), wxEmptyString);
            // Добавляем запись в список
            index = m_ListCtrl->InsertItem(m_ListCtrl->GetItemCount(), tmp_str);
            // Получаем отчество
            tmp_str = curnode->GetPropVal(wxT("Patronymic"), wxEmptyString);
            // Устанавливаем значение во второй колонке
            m_ListCtrl->SetItem(index, 1, tmp_str);
            // Получаем фамилию
            tmp_str = curnode->GetPropVal(wxT("Surname"), wxEmptyString);
            // Устанавливаем значение в третьей колонке
            m_ListCtrl->SetItem(index, 2, tmp_str);            
        }
        // Переходим к следующему элементу документа
        curnode = curnode->GetNext();
    }
    // Разрешаем отрисовку для списка
    m_ListCtrl->Thaw();
}

void MyFrame::SaveToFile(wxString filename)
{
    // Создаем документ
    wxXmlDocument doc;
    // Создаем корневой элемент
    wxXmlNode * root_node = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Notebook"));    
    doc.SetRoot(root_node);
    wxXmlNode * curnode;
    wxListItem item;
    /*
    Для получения значения из ячейки списка нам нужно установить маску для wxListItem,
    которая отвечает за то, какие параметры элемента мы должны получить...
    */
    item.SetMask(wxLIST_MASK_TEXT);
    // Проходимся по всем строкам списка
    for(long i = 0; i < m_ListCtrl->GetItemCount(); i++)
    {
        // Устанавливаем номер записи для wxListItem
        item.SetId(i);
        // Создаем новый элемент XML-документа
        curnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("NotebookRecord"));
        // Устанавливаем номер колонки в 0
        item.SetColumn(0);
        // Получаем данные для нужной нам ячейки
        m_ListCtrl->GetItem(item);
        // Добавляем параметр Name для нашего XML-элемента
        curnode->AddProperty(wxT("Name"), item.GetText());
        item.SetColumn(1);
        m_ListCtrl->GetItem(item);
        // Добавляем параметр Patronymic для нашего XML-элемента
        curnode->AddProperty(wxT("Patronymic"), item.GetText());
        item.SetColumn(2);
        m_ListCtrl->GetItem(item);
        // Добавляем параметр Surname для нашего XML-элемента
        curnode->AddProperty(wxT("Surname"), item.GetText());
        // Добавляем наш элемент к корневому
        root_node->AddChild(curnode);
    }
    // Сохраняем документ
    doc.Save(filename);
}

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

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



Опубликовал admin
8 Фев, Среда 2006г.



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