Phone Book Architecture Overview
Andy Liu ( Windbell )
May 29, 2007
l What does photo book can do?
1. Supporting adding
2. Supporting modifying
3. Supporting deleting
4. supporting finding
5. Supporting file reading and writing.
l Architecture Overview
1. Class diagram
2. Overview of class Phone Book and supporting class
All core class and API about Phone Book are in PB namespace.
l Class PB::CPhBookitem define content of each item
l Class PB::CPhBook defines a Phone book, which contains a list of PB::CPhBookitem items. It provides a serial of operation function on Phone book, such as adding, deleting, editing and finding, etc. It also support import and export data.
l Class PB::CDataSource, a interface which define where the data from and where the data be transferred. Such as Text file, Database, Excel application, etc.
l Class PB::CIOStreamDataSource, a concrete class which implement export and import function. It supporting read data from .txt and write into it.
3. Overview of class CPhoneBookDoc
We usually manage data in class CXXXDoc, so it has an instance of PB::CPhBook. It is a bridge between UI and Core API. Any operation on phone book data should via it.
l OnOpenDocument(LPCTSTR lpszPathName)
In it call CPhBook::ImportData() functions implement read data from a file.
l OnSaveDocument(LPCTSTR lpszPathName)
In it call CPhBook::ExportData() functions implement write data into a file.
4. Overview of class CPhoneView
Show data on UI and provide some UI interface , such as dialog, form which get user’s data. It has a ListCtrl control, from which show data in report style.
l Class CAddItemDialog
A UI interface for adding a phone book item.
l Class CModItemDialog
A UI interface for editing a phone book item.
l Class CFindItemDialog
A UI interface for finding a phone book item.
l Tricks and tips
1. How to use ListCtrl control?
l Set style of ListCtrl
... {
//Get reference of ListCtrl
CListCtrl &refListCtrl = GetListCtrl();
//Create image list
m_imagelist.Create(16,16,TRUE,2,2);
m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
refListCtrl.SetImageList(&m_imagelist,LVSIL_SMALL);
//Set style of Font
m_font.CreateFont(16, 0,0,0,FW_NORMAL, 0,0,0,
DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, _T("Arial"));
refListCtrl.SetFont(&m_font);
refListCtrl.ModifyStyle( LVS_TYPEMASK,LVS_REPORT );
refListCtrl.SetExtendedStyle( LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_ONECLICKACTIVATE );
refListCtrl.SetBkColor(RGB(247,247,255));
refListCtrl.SetTextColor(RGB(0,0,255));
refListCtrl.SetTextBkColor(RGB(247,247,255));
//Get field information and set the header for the LIstCtrl.
int numOfField = 0;
Tstring *pFiledNameArray = NULL;
PB::GetCPhBookInfo( numOfField, &pFiledNameArray );
for( int i = 0; i < numOfField; ++i )
...{
refListCtrl.InsertColumn( i, CString(pFiledNameArray[i].c_str()), LVCFMT_LEFT, 180 );
}
delete []pFiledNameArray;
}
l Display
... {
CListCtrl &refListCtrl = GetListCtrl();
refListCtrl.DeleteAllItems();
int num = refListCtrl.GetItemCount();
ASSERT( num == 0);
PB::CPhBook &refPhBook = m_pDoc->GetPhBook();
int size = refPhBook.GetSize();
if( 0 == size )
return ;
const CPhBookItemArrayType *data = refPhBook.GetData();
assert( data );
const PB::CPhBookItem *pTempCPhBookItem = NULL;
Tstring name;
Tstring sex;
Tstring number;
Tstring type;
Tstring address;
for( int i = 0; i < size ; ++i )
...{
pTempCPhBookItem = &((*data)[i]);
name = pTempCPhBookItem->GetName();
sex = PB::SexAsStr( pTempCPhBookItem->GetSex() );
number = pTempCPhBookItem->GetNumber();
type = PB::PhTypeAsStr( pTempCPhBookItem->GetType() );
address = pTempCPhBookItem->GetAddress();
refListCtrl.InsertItem( i, PB::StrToCStr( name ) );
refListCtrl.SetItemText(i, 1, PB::StrToCStr( sex ) );
refListCtrl.SetItemText(i, 2, PB::StrToCStr( number ) );
refListCtrl.SetItemText(i, 3, PB::StrToCStr( type ) );
refListCtrl.SetItemText(i, 4, PB::StrToCStr( address ) );
}
}
l Get multi-Selected set
int countSelected = refListCtrl.GetSelectedCount();
int * pSelected = new int [countSelected];
int index = 0 ;
POSITION pos = refListCtrl.GetFirstSelectedItemPosition();
while (pos)
pSelected[index ++ ] = refListCtrl.GetNextSelectedItem(pos);
l Delete multi-Selected item.
... {
// TODO: Add your control notification handler code here
CListCtrl &refListCtrl = GetListCtrl();
int countDel = refListCtrl.GetSelectedCount();
if( 0 == countDel )
...{
MessageBox(_T("No selected item to delete!"),_T("Wrong"),MB_ICONINFORMATION);
return;
}
int *pDelRows = new int[countDel];
int index = 0;
POSITION pos = refListCtrl.GetFirstSelectedItemPosition();
while (pos)
pDelRows[index++] = refListCtrl.GetNextSelectedItem(pos);
while (index--)
...{
m_pDoc->GetPhBook().Del( pDelRows[index] );
refListCtrl.DeleteItem(pDelRows[index]);
}
delete[] pDelRows;
}
l Set the found items as selected state.
... {
//reset state for current selected items.
CListCtrl &refListCtrl = GetListCtrl();
int countSelected = refListCtrl.GetSelectedCount();
int *pSelected = new int[countSelected];
int index = 0;
POSITION pos = refListCtrl.GetFirstSelectedItemPosition();
while (pos)
pSelected[index++] = refListCtrl.GetNextSelectedItem(pos);
for( int i = 0; i < countSelected; ++i )
refListCtrl.SetItemState( pSelected[i], 0, LVIS_SELECTED);
delete []pSelected;
pSelected = NULL;
//Find
//...
//End find
//Set the found items as selected state.
for( int i = 0; i < countSelected; ++i )
refListCtrl.SetItemState( pSelected[i], LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED);
delete []pSelected;
pSelected = NULL;
}
2. How to use ComboBox control?
l Initialize CombolBox control
m_TypeComb.AddString( _T( " Friend " ));
m_TypeComb.AddString( _T( " Classmate " ));
m_TypeComb.AddString( _T( " Colleague " ));
m_TypeComb.AddString( _T( " Other " ));
if ( _T( " Family " ) == m_Type )
m_TypeComb.SetCurSel( 0 );
else if ( _T( " Friend " ) == m_Type )
m_TypeComb.SetCurSel( 1 );
else if ( _T( " Classmate " ) == m_Type )
m_TypeComb.SetCurSel( 2 );
else if ( _T( " Colleague " ) == m_Type )
m_TypeComb.SetCurSel( 3 );
else
m_TypeComb.SetCurSel( 4 );
UpdateData( FALSE );
l Update value of CombolBox contro
l Get value of CombolBox contro
m_TypeComb.GetLBText( nIndex, m_Type );
3. How to use Radio button?
l Initialize Radio button?
CheckRadioButton(IDC_RADIO1,IDC_RADIO2,IDC_RADIO1);
else
CheckRadioButton(IDC_RADIO1,IDC_RADIO2,IDC_RADIO2);
l Update value of Radio button?
l Get value of Radio button?
4. other tricks and tips.
l Convert between CString and std::string.
#define Tstring std::wstring
#else
#define Tstring std::string
#endif
namespace PB
... {
//String convert function.
Tstring CStrToStr( const CString &cstr ); //From MFC::CString to STD::string
CString StrToCStr( const Tstring &str); //From STD::string to MFC::CString
}
Tstring PB::CStrToStr( const CString & cstr )
... {
int sizeOfString = (cstr.GetLength() + 1);
LPTSTR lpsz = new TCHAR[ sizeOfString ];
_tcscpy_s(lpsz, sizeOfString, cstr);
Tstring s(lpsz);
delete []lpsz;
return s;
}
CString PB::StrToCStr( const Tstring & str)
... {
return CString( str.c_str() );
}
l Validate for user’s input parameter
Handle change message.
... {
if( m_hasName && m_hasNumber && m_hasAddress)
GetDlgItem( IDOK )->EnableWindow(TRUE);
else
GetDlgItem( IDOK )->EnableWindow(FALSE);
}
void CModItemDialog::OnEnChangeEditModname()
... {
// TODO: Add your control notification handler code here
UpdateData(true);
if( m_Name != _T("") )
m_hasName = true;
else
m_hasName = false;
_CheckInput();
}
l Doesn’t use serialize mechanism provided by MFC.
Override CDocument::OnOpenDocument( LPCTSTR );
CDocument::OnSaveDocument( LPCTSTR );
l In based on single-document project, there is only one instance of class CDocument in application, despite user do [ open file ] operation many times. SDI document will reuse the instance. So we should add reinitialization code in CDocument::OnNewDocument();