Продолжение статьи, рассказывающей о работе с базами данных в wxWidgets. Первую чать статьи можно почитать здесь.
В предыдущей части мы рассмотрели настройку проекта, сборку дополнительных библиотек и создание графического интерфейса приложения. В этой часит рассказывается как создать классы бизнес-логики с помощью утилиты wxARG и о том, как эти классы использовать в своем проекте.
Устанавливаем утилиту wxARG, копируем из папки, куда была установлена wxARG два файла wxActiveRecord.h и wxActiveRecord.cpp в папку SQLiteTest/wxActiveRecord
Здесь хотелось бы отметить, что файлы wxActiveRecord.h и wxActiveRecord.cpp из последней верчии wxARG-1.2.0-rc2 отлично собрались вместе с тестовым проектом, хотя сама утилита работала нестабильно, из-за чего мне пришлось установить поверх нее более раннюю версию wxARG-1.1.0, которая работала нормально.
Итак, запускаем wxARG и выбираем пункт меню File -> Connect to database, в диалоговом окне Database Connection указываем тип базы данных SQLite3 Database и путь к файлу addressbook.db, созданному нашим тестовым приложением. Жмем Connect
В диалоговом окне Tables выбираем таблицы groups и persons. Жмем OK
После этого в левой части главного окна wxARG появится список с выбранными таблицами.
Каждая таблица нашей базы данных имеет ключевое поле id, поэтому на вкладке Properties для каждой таблицы в поле ID Field мы указываем поле id и включаем маркер Overwrite (delete custom stuff).
В нашей базе данных между таблицами groups и persons существует связь один-ко-многим, т.е. каждая группа может содержать множество контактов адресной книги. Переходим на вкладку Relations.
Для таблицы groups:
– Жмем кнопку Has Many
– В диалоговом окне Relation Properties указываем название таблицы со стороны “многие”, в нашем случае это таблица persons
– Указываем поле внешнего ключа в таблице persons. В нашем случае это groupid
Значения остальных параметров можно оставить без изменений.
Для таблицы persons:
Значения остальных параметров можно оставить без изменений.
В поле Output Dir указываем папку проекта SQLiteTest и жмем Generate
После всех проделанных операций, в папке с проектом SQLiteTest должны появиться файлы:
Эти файлы нам необходимо добавить в проект.
После того, как все необходимые файлы добавлены, можно приступать к внесению изменений в исходный код.
Для начала в файле wxActiveRecord.h не обходимо раскомментировать строку с макросом AR_USE_SQLITE
, который указывает, что мы используем СУБД SQLite. В файле wxActiveRecord.cpp необходимо исправить путь к заголовочному файлу wxActiveRecord.h
wxActiveRecord.h
... // COMMENT OUT THE ONES YOU DON'T USE //#define AR_USE_POSTGRESQL #define AR_USE_SQLITE //#define AR_USE_MYSQL //#define AR_USE_FIREBIRD ...
wxActiveRecord.cpp
... #include "wxActiveRecord.h" //begin WX_ACTIVE_RECORD ...
Теперь, если посмотреть на исходный код файлов, сгенерированных утилитой wxARG, то можно заметить, что каждая пара .h/.cpp файлов содержит описание и реализацию трех классов:
где XXX – название таблицы.
И после всего сказанного, вооружившись полученными знаниями, продолжим наш “happy coding”.
SQLiteTestApp.h
... #include <sqliteDatabaseLayer.h> #include "Group.h" #include "Person.h" class SQLiteTestApp : public wxApp { Group * m_GroupTable; Person * m_PersonTable; ... public: ... Group * GetGroupTable(); Person * GetPersonTable(); }; ...
SQLiteTestApp.cpp
... int SQLiteTestApp::OnExit() { wxDELETE(m_PersonTable); wxDELETE(m_GroupTable); ... } bool SQLiteTestApp::ConnectToDatabase() { ... try { m_GroupTable = new Group(wxGetApp().GetDatabase(), wxT("groups")); m_PersonTable = new Person(wxGetApp().GetDatabase(), wxT("persons")); } catch(DatabaseLayerException & e) { wxActiveRecord::ProcessException(e); } return true; } ... Group * SQLiteTestApp::GetGroupTable() { return m_GroupTable; } Person * SQLiteTestApp::GetPersonTable() { return m_PersonTable; }
Итак, мы добавили новые члены класса SQLiteTestApp
, обеспечивающие доступ к таблицам базы данных и теперь можно приступать к созданию GUI.
Дистрибутив wxWidgets содержит несколько десятков свободно распространяемых иконок, которые мы можем использовать в нашем приложении. Создадим папку SQLiteTest/art и скопируем в нее файлы
SQLiteTestMainFrame.h
#ifndef _SQLITE_TEST_MAINFRAME_H #define _SQLITE_TEST_MAINFRAME_H #include <wx/wx.h> #include <wx/toolbar.h> #include <wx/listbox.h> #include <wx/listctrl.h> #include <wx/html/htmlwin.h> class SQLiteTestMainFrame : public wxFrame { wxListBox * m_GroupsListBox; wxListView * m_PersonsListView; wxHtmlWindow * m_PersonInfoPanel; void CreateControls(); wxToolBar * CreateToolBar(); public: SQLiteTestMainFrame(); bool Create(wxWindow * parent, wxWindowID id, const wxString & title); DECLARE_EVENT_TABLE() void OnExit(wxCommandEvent & event); }; #endif
SQLiteTestMainFrame.cpp
... #include <wx/splitter.h> #include "new.xpm" #include "delete.xpm" #include "addbookm.xpm" #include "delbookm.xpm" enum { ID_GROUPS_LISTBOX = 10001, ID_PERSONS_LISTCTRL, ID_PERSON_INFO_PANEL, ID_ADD_GROUP, ID_DELETE_GROUP, ID_ADD_PERSON, ID_DELETE_PERSON }; ... void SQLiteTestMainFrame::CreateControls() { 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); wxSplitterWindow * splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxSize(500, 400), wxSP_3DSASH); splitter->SetMinimumPaneSize(100); sizer->Add(splitter, 1, wxEXPAND); m_GroupsListBox = new wxListBox(splitter, ID_GROUPS_LISTBOX, wxDefaultPosition, wxDefaultSize); wxSplitterWindow * personsplitter = new wxSplitterWindow(splitter, wxID_ANY, wxDefaultPosition, wxSize(500, 400), wxSP_3DSASH); personsplitter->SetMinimumPaneSize(100); m_PersonsListView = new wxListView(personsplitter, ID_PERSONS_LISTCTRL, wxDefaultPosition, wxDefaultSize, wxLC_REPORT); m_PersonsListView->InsertColumn(0, _("First Name"), wxLIST_FORMAT_LEFT, 120); m_PersonsListView->InsertColumn(1, _("Last Name"), wxLIST_FORMAT_LEFT, 120); m_PersonsListView->InsertColumn(2, _("E-Mail"), wxLIST_FORMAT_LEFT, 130); m_PersonsListView->InsertColumn(3, _("Phone"), wxLIST_FORMAT_LEFT, 130); m_PersonInfoPanel = new wxHtmlWindow(personsplitter, ID_PERSON_INFO_PANEL); personsplitter->SetSashGravity(1.0); splitter->SplitVertically(m_GroupsListBox, personsplitter, 160); personsplitter->SplitHorizontally(m_PersonsListView, m_PersonInfoPanel, personsplitter->GetSize().GetHeight()-180); SetToolBar(CreateToolBar()); CreateStatusBar(2); Centre(); } wxToolBar * SQLiteTestMainFrame::CreateToolBar() { wxToolBar * toolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT|wxTB_TEXT); toolBar->AddTool(ID_ADD_GROUP, _("Add Group"), wxBitmap(addbookm_xpm)); toolBar->AddTool(ID_DELETE_GROUP, _("Remove Group"), wxBitmap(delbookm_xpm)); toolBar->AddSeparator(); toolBar->AddTool(ID_ADD_PERSON, _("Add Person"), wxBitmap(new_xpm)); toolBar->AddTool(ID_DELETE_PERSON, _("Remove Person"), wxBitmap(delete_xpm)); toolBar->Realize(); return toolBar; } ...
Для работы с классом wxHtmlWindow в свойствах проекта вразделе Linker -> Input в настройках Additional Dependencies нам необходимо добавить библиотеку wxmsw28ud_html.lib для конфигурации Debug и wxmsw28u_html.lib для конфигурации Release
После всех внесенных изменений, у нас должно получиться нечто подобное:
Отлично, интерфейс приложения готов, теперь можно приступить к реализации функционала.
RecordIDClientData.h
#ifndef _RECORD_ID_CLIENT_DATA_H #define _RECORD_ID_CLIENT_DATA_H #include <wx/clntdata.h> class RecordIDClientData : public wxClientData { int m_ID; public: RecordIDClientData(int id) : m_ID(id) {} int GetID() {return m_ID;} void SetID(int id) {m_ID = id;} }; #endif
SQLiteTestMainFrame.h
... #include <wx/wx.h> #include <wx/toolbar.h> #include <wx/listbox.h> #include <wx/listctrl.h> #include <wx/html/htmlwin.h> class SQLiteTestMainFrame : public wxFrame { ... void FillGroupsList(); void FillPersonsList(int groupid); ... DECLARE_EVENT_TABLE() void OnExit(wxCommandEvent & event); void OnGroupListBoxSelected(wxCommandEvent & event); void OnPersonListViewSelected(wxListEvent & event); void OnPersonInfoPanelLinkClicked(wxHtmlLinkEvent & event); }; ...
SQLiteTestMainFrame.cpp
void SQLiteTestMainFrame::FillGroupsList() { m_GroupsListBox->Freeze(); m_GroupsListBox->Clear(); GroupRowSet * allGroups = wxGetApp().GetGroupTable()->All(); for(unsigned long i = 0; i < allGroups->Count(); ++i) { m_GroupsListBox->Append(allGroups->Item(i)->name, new RecordIDClientData(allGroups->Item(i)->id)); } if(m_GroupsListBox->GetCount()) { m_GroupsListBox->SetSelection(0); RecordIDClientData * data = (RecordIDClientData *) m_GroupsListBox->GetClientObject(m_GroupsListBox->GetSelection()); if(data) { FillPersonsList(data->GetID()); } } wxGetApp().GetGroupTable()->CollectRowSet(allGroups); m_GroupsListBox->Thaw(); } void SQLiteTestMainFrame::FillPersonsList(int groupid) { m_PersonsListView->Freeze(); m_PersonsListView->DeleteAllItems(); GroupRow * thisGroup = wxGetApp().GetGroupTable()->Id(groupid); if(thisGroup) { PersonRowSet * allPersons = thisGroup->GetPersons(); long item(0); for(unsigned long i = 0; i < allPersons->Count(); ++i) { item = m_PersonsListView->InsertItem(item, allPersons->Item(i)->first_name); m_PersonsListView->SetItem(item, 1, allPersons->Item(i)->last_name); m_PersonsListView->SetItem(item, 2, allPersons->Item(i)->email); m_PersonsListView->SetItem(item, 3, allPersons->Item(i)->phone); m_PersonsListView->SetItemData(item, (long)allPersons->Item(i)->id); } thisGroup->CollectRowSet(allPersons); if(m_PersonsListView->GetItemCount()) { m_PersonsListView->Select(0); } else { m_PersonInfoPanel->SetPage(wxT("<html><body></body></html>")); } } wxGetApp().GetGroupTable()->CollectRow(thisGroup); m_PersonsListView->Thaw(); } void SQLiteTestMainFrame:: OnGroupListBoxSelected(wxCommandEvent & event) { RecordIDClientData * data = (RecordIDClientData *)event.GetClientObject(); if(data) { FillPersonsList(data->GetID()); } } void SQLiteTestMainFrame::OnPersonListViewSelected(wxListEvent & event) { long personid = event.GetData(); PersonRow * person = wxGetApp().GetPersonTable()->Id((int)personid); if(person) { m_PersonInfoPanel->SetPage(wxString::Format( wxT("<html><body><h3>%s %s<h3><body><html>"), person->first_name, person->last_name)); m_PersonInfoPanel->AppendToPage(wxString::Format( wxT("<b>Gender: </b> %s"), (person->gender?wxT("Male"):wxT("Female")))); m_PersonInfoPanel->AppendToPage(wxT("<hr />")); m_PersonInfoPanel->AppendToPage(wxString::Format( wxT("<b>Address: </b> %s<br />"), person->address.GetData())); m_PersonInfoPanel->AppendToPage(wxString::Format( wxT("<b>City: </b> %s<br />"), person->city.GetData())); m_PersonInfoPanel->AppendToPage(wxString::Format( wxT("<b>Country: </b> %s"), person->country.GetData())); m_PersonInfoPanel->AppendToPage(wxT("<hr />")); m_PersonInfoPanel->AppendToPage( wxString::Format(wxT("<b>Phone: </b> %s<br />"), person->phone.GetData())); m_PersonInfoPanel->AppendToPage(wxString::Format( wxT("<b>E-mail: </b> <a href=\"mailto:%s\">%s</a><br />"), person->email, person->email.GetData())); } else { m_PersonInfoPanel->SetPage( _("<html><body><h3>Can't find info about selected person<h3><body><html>")); } } void SQLiteTestMainFrame:: OnPersonInfoPanelLinkClicked(wxHtmlLinkEvent & event) { #if defined(__WXMSW__) ShellExecute(NULL, NULL, event.GetLinkInfo().GetHref().GetData(), NULL, NULL, SW_SHOW); #else wxExecute(event.GetLinkInfo().GetHref()); #endif }
Список в левой части окна содержит названия групп. Каждый элемент списка содержит код группы. Привязка данных к элементам списка реализована с помощью объектов класса RecordIDClientData, каждый объект которого содержит код группы. Класс RecordIDClientData является производным от wxClientData и его использование обеспечивает автоматическую очистку памяти при удалении элемента списка. Доступ к данным, ассоциированным с элементом списка групп, производится посредством метода GetClientObject класса wxListBox
При выборе записи в списке групп, список контактов в правой части окна заполняется данными контактов данной группы.
При выборе элемента списка контактов, информационное поле в нижней части окна заполняется данными контакта, связанного с выбранным элементом списка. Каждый элемент списка контактов содержит в поле данных код контакта. Доступ к полю данных производится посредством метода GetItemData класса wxListView
При нажатии на ссылку с адресом электронной почты в информационном поле, создается новое письмо в почтовом клиенте, назначенном по умолчанию.
Итак, с отображением данных мы закончили. Теперь нужно реализовать добавление новой записи в таблицу и удаление записей из таблицы.
Для начала создадим диалоговые окна вода данных.
EditGroupDialog.h
#ifndef _EDIT_GROUP_DIALOG_H #define _EDIT_GROUP_DIALOG_H #include <wx/wx.h> class EditGroupDialog : public wxDialog { wxString m_GroupName; wxString m_GroupDescription; void CreateControls(); public: EditGroupDialog(wxWindow * parent); bool Create(wxWindow * parent, wxWindowID id, const wxString title); const wxString & GetGroupName(); void SetGroupName(const wxString & value); const wxString & GetGroupDescription(); void SetGroupDescription(const wxString & value); }; #endif
EditGroupDialog.cpp
#include "EditGroupDialog.h" #include <wx/valgen.h> enum { ID_EGD_NAME_TEXTCTRL = 10001, ID_EGD_DESCRIPTION_TEXTCTRL }; EditGroupDialog::EditGroupDialog(wxWindow * parent) { Create(parent, wxID_ANY, _("Editing group")); } bool EditGroupDialog::Create(wxWindow * parent, wxWindowID id, const wxString title) { bool res = wxDialog::Create(parent, id, title); if(res) { CreateControls(); } return res; } void EditGroupDialog::CreateControls() { wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL); SetSizer(sizer); wxStaticText * nameLabel = new wxStaticText(this, wxID_ANY, _("Name:")); wxStaticText * descriptionLabel = new wxStaticText(this, wxID_ANY, _("Description:")); wxTextCtrl * nameEdit = new wxTextCtrl(this, ID_EGD_NAME_TEXTCTRL, wxEmptyString); wxTextCtrl * descriptionEdit = new wxTextCtrl(this, ID_EGD_DESCRIPTION_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxSize(-1, 150), wxTE_MULTILINE); nameEdit->SetValidator(wxGenericValidator(&m_GroupName)); descriptionEdit->SetValidator(wxGenericValidator(&m_GroupDescription)); wxFlexGridSizer * fg_sizer = new wxFlexGridSizer(2, 2, 0, 0); fg_sizer->Add(nameLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(nameEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(descriptionLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(descriptionEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->AddGrowableCol(1); sizer->Add(fg_sizer, 1, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5); sizer->Add(CreateButtonSizer(wxID_OK|wxID_CANCEL), 0, wxALIGN_RIGHT|wxALL, 5); } const wxString & EditGroupDialog::GetGroupName() { return m_GroupName; } void EditGroupDialog::SetGroupName(const wxString & value) { m_GroupName = value; } const wxString & EditGroupDialog::GetGroupDescription() { return m_GroupDescription; } void EditGroupDialog::SetGroupDescription(const wxString & value) { m_GroupDescription = value; }
EditPersonDialog.h
#ifndef _EDIT_PERSON_DIALOG_H #define _EDIT_PERSON_DIALOG_H #include <wx/wx.h> class EditPersonDialog : public wxDialog { wxString m_FirstName; wxString m_LastName; wxString m_Address; wxString m_City; wxString m_Country; wxString m_Email; wxString m_Phone; void CreateControls(); public: EditPersonDialog(wxWindow * parent); bool Create(wxWindow * parent, wxWindowID id, const wxString title); const wxString & GetFirstName(); const wxString & GetLastName(); const wxString & GetAddress(); const wxString & GetCity(); const wxString & GetCountry(); const wxString & GetEmail(); const wxString & GetPhone(); }; #endif
EditPersonDialog.cpp
#include "EditPersonDialog.h" #include <wx/valgen.h> enum { ID_EPD_FIRSTNAME_TEXTCTRL = 10001, ID_EPD_LASTNAME_TEXTCTRL, ID_EPD_ADDRESS_TEXTCTRL, ID_EPD_CITY_TEXTCTRL, ID_EPD_COUNTRY_TEXTCTRL, ID_EPD_EMAIL_TEXTCTRL, ID_EPD_PHONE_TEXTCTRL }; EditPersonDialog::EditPersonDialog(wxWindow * parent) { Create(parent, wxID_ANY, _("Editing person")); } bool EditPersonDialog::Create(wxWindow * parent, wxWindowID id, const wxString title) { bool res = wxDialog::Create(parent, id, title); if(res) { CreateControls(); } return res; } void EditPersonDialog::CreateControls() { wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL); SetSizer(sizer); wxStaticText * firstnameLabel = new wxStaticText(this, wxID_ANY, _("First Name:")); wxStaticText * lastnameLabel = new wxStaticText(this, wxID_ANY, _("Last Name:")); wxStaticText * addressLabel = new wxStaticText(this, wxID_ANY, _("Address:")); wxStaticText * cityLabel = new wxStaticText(this, wxID_ANY, _("City:")); wxStaticText * countryLabel = new wxStaticText(this, wxID_ANY, _("Country:")); wxStaticText * emailLabel = new wxStaticText(this, wxID_ANY, _("E-mail:")); wxStaticText * phoneLabel = new wxStaticText(this, wxID_ANY, _("Phone:")); wxTextCtrl * firstnameEdit = new wxTextCtrl(this, ID_EPD_FIRSTNAME_TEXTCTRL, wxEmptyString); wxTextCtrl * lastnameEdit = new wxTextCtrl(this, ID_EPD_LASTNAME_TEXTCTRL, wxEmptyString); wxTextCtrl * addressEdit = new wxTextCtrl(this, ID_EPD_ADDRESS_TEXTCTRL, wxEmptyString); wxTextCtrl * cityEdit = new wxTextCtrl(this, ID_EPD_CITY_TEXTCTRL, wxEmptyString); wxTextCtrl * countryEdit = new wxTextCtrl(this, ID_EPD_COUNTRY_TEXTCTRL, wxEmptyString); wxTextCtrl * emailEdit = new wxTextCtrl(this, ID_EPD_EMAIL_TEXTCTRL, wxEmptyString); wxTextCtrl * phoneEdit = new wxTextCtrl(this, ID_EPD_PHONE_TEXTCTRL, wxEmptyString); firstnameEdit->SetMinSize(wxSize(150,-1)); firstnameEdit->SetValidator(wxGenericValidator(&m_FirstName)); lastnameEdit->SetValidator(wxGenericValidator(&m_LastName)); addressEdit->SetValidator(wxGenericValidator(&m_Address)); cityEdit->SetValidator(wxGenericValidator(&m_City)); countryEdit->SetValidator(wxGenericValidator(&m_Country)); emailEdit->SetValidator(wxGenericValidator(&m_Email)); phoneEdit->SetValidator(wxGenericValidator(&m_Phone)); wxFlexGridSizer * fg_sizer = new wxFlexGridSizer(2, 2, 0, 0); fg_sizer->Add(firstnameLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(firstnameEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(lastnameLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(lastnameEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(addressLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(addressEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(cityLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(cityEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(countryLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(countryEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(emailLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(emailEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(phoneLabel, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->Add(phoneEdit, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5); fg_sizer->AddGrowableCol(1); sizer->Add(fg_sizer, 1, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5); sizer->Add(CreateButtonSizer(wxID_OK|wxID_CANCEL), 0, wxALIGN_RIGHT|wxALL, 5); sizer->Fit(this); } const wxString & EditPersonDialog::GetFirstName() { return m_FirstName; } const wxString & EditPersonDialog::GetLastName() { return m_LastName; } const wxString & EditPersonDialog::GetAddress() { return m_Address; } const wxString & EditPersonDialog::GetCity() { return m_City; } const wxString & EditPersonDialog::GetCountry() { return m_Country; } const wxString & EditPersonDialog::GetEmail() { return m_Email; } const wxString & EditPersonDialog::GetPhone() { return m_Phone; }
Теперь можно приступать к написанию обработчиков событий от кнопок на панели инструментов.
SQLiteTestMainFrame.h
... class SQLiteTestMainFrame : public wxFrame { ... void OnAddGroup(wxCommandEvent & event); void OnRemoveGroup(wxCommandEvent & event); void OnAddPerson(wxCommandEvent & event); void OnRemovePerson(wxCommandEvent & event); void OnRemoveGroupUpdateUI(wxUpdateUIEvent & event); void OnAddPersonUpdateUI(wxUpdateUIEvent & event); void OnRemovePersonUpdateUI(wxUpdateUIEvent & event); }; ...
SQLiteTestMainFrame.cpp
... void SQLiteTestMainFrame::OnAddGroup(wxCommandEvent & event) { EditGroupDialog * dlg = new EditGroupDialog(this); if(dlg->ShowModal() == wxID_OK) { GroupRow * newGroup = wxGetApp().GetGroupTable()->New(); newGroup->name = dlg->GetGroupName(); newGroup->description = dlg->GetGroupDescription(); newGroup->Save(); wxGetApp().GetGroupTable()->CollectRow(newGroup); FillGroupsList(); } dlg->Destroy(); } void SQLiteTestMainFrame::OnRemoveGroup(wxCommandEvent & event) { int selection = m_GroupsListBox->GetSelection(); RecordIDClientData * data = (RecordIDClientData *) m_GroupsListBox->GetClientObject(selection); if(data) { GroupRow * thisGroup = wxGetApp().GetGroupTable()->Id(data->GetID()); if(thisGroup && (wxMessageBox(_("Do you really want to delete this group?"), _("Delete group"), wxYES_NO) == wxYES)) { PersonRowSet * thisPersons = thisGroup->GetPersons(); for(unsigned long i = 0; i < thisPersons->Count(); ++i) { thisPersons->Item(i)->Delete(); } thisGroup->CollectRowSet(thisPersons); thisGroup->Delete(); wxGetApp().GetGroupTable()->CollectRow(thisGroup); m_GroupsListBox->Delete(selection); if(m_GroupsListBox->GetCount()) { m_GroupsListBox->SetSelection(selection < (int)m_GroupsListBox->GetCount() ? selection : 0); data = (RecordIDClientData *)m_GroupsListBox->GetClientObject( m_GroupsListBox->GetSelection()); if(data) { FillPersonsList(data->GetID()); } } } } } void SQLiteTestMainFrame::OnAddPerson(wxCommandEvent & event) { RecordIDClientData * data = (RecordIDClientData *) m_GroupsListBox->GetClientObject(m_GroupsListBox->GetSelection()); if(data) { GroupRow * thisGroup = wxGetApp().GetGroupTable()->Id(data->GetID()); if(thisGroup) { EditPersonDialog * dlg = new EditPersonDialog(this); if(dlg->ShowModal() == wxID_OK) { PersonRow * newPerson = wxGetApp().GetPersonTable()->New(); newPerson->groupid= thisGroup->id; newPerson->first_name = dlg->GetFirstName(); newPerson->last_name = dlg->GetLastName(); newPerson->address = dlg->GetAddress(); newPerson->city = dlg->GetCity(); newPerson->country = dlg->GetCountry(); newPerson->email = dlg->GetEmail(); newPerson->phone = dlg->GetPhone(); newPerson->Save(); wxGetApp().GetPersonTable()->CollectRow(newPerson); FillPersonsList(thisGroup->id); } dlg->Destroy(); } wxGetApp().GetGroupTable()->CollectRow(thisGroup); } } void SQLiteTestMainFrame::OnRemovePerson(wxCommandEvent & event) { long selection = m_PersonsListView->GetFirstSelected(); PersonRow * thisPerson = wxGetApp().GetPersonTable()->Id( (int)m_PersonsListView->GetItemData(selection)); if(thisPerson && (wxMessageBox(_("Do you really want to delete this record?"), _("Delete person"), wxYES_NO) == wxYES)) { int groupid = thisPerson->groupid; thisPerson->Delete(); wxGetApp().GetPersonTable()->CollectRow(thisPerson); m_PersonsListView->DeleteItem(selection); if(m_PersonsListView->GetItemCount()) { m_PersonsListView->Select(wxMin(selection, m_PersonsListView->GetItemCount()-1)); } } } void SQLiteTestMainFrame:: OnRemoveGroupUpdateUI(wxUpdateUIEvent & event) { event.Enable(m_GroupsListBox->GetSelection() >= 0); } void SQLiteTestMainFrame:: OnAddPersonUpdateUI(wxUpdateUIEvent & event) { event.Enable(m_GroupsListBox->GetSelection() >= 0); } void SQLiteTestMainFrame:: OnRemovePersonUpdateUI(wxUpdateUIEvent & event) { event.Enable(m_PersonsListView->GetFirstSelected() >= 0); } ...
Как видно, кнопка удаления группы и кнопка добавления контакта активна только в случае, если есть активная запись в списке групп. Кнопка удаления контакта становится активной только в случае, если есть активная запись в списке контактов.
При удалении группы удаляются и все связанные с ней контакты.
Ну вот. Мы закончили. Теперь собираем Release-версию программы и тестируем. Можно переходить к созданию проекта под Linux
Продолжение статьи можно почитать здесь.
Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…
I can see that there is still a lot of topics at wxWidgets forums related…
I've just published the source code of wxToolBox component and a couple of sample apps at…
Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…
Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…
View Comments
На счет wxArg что то я нигде не могу его достать все ссылки битые каталоги пустые
На wxCode переходишь в раздел загрузок на sourceforge и там есть инсталлер.
НО. Для простых баз он нормально работает, а вот для более сложных, да еще и с blob'ами надо будет руками подправлять.
Ну и там еще в паре мест есть трабла, isNew переменная-член класса записи в конструкторе переобъявляется как локальная, надо руками убирать кусок кода, а то wxARG не будет знать что новая запись добавлена.
Проект, как я понимаю, больше не сапортится. Я начал писать собственный кодогенератор, но там все только в зачаточном состоянии и я не знаю когда у меня будет время все закончить.
http://wxcode.sourceforge.net/components/activerecord/tutorial/wxARG-tutorial.php
I cannot download wxARG http://wxcode.sourceforge.net/components/activerecord/tutorial/wxARG-tutorial.zip
I think you should ask author of wxARG regarding this point.