构思确定通讯录的功能
1. 基本功能
- 添加联系人
- 删除联系人
- 修改联系人
- 显示联系人信息
2. 附加功能
- 查找联系人
- 读取保存联系人信息
3. 创意小功能
- 显示备注
- 电话号码必须为11位
- 双击报表视图中联系人即可修改联系人信息
- 查找联系人时报表视图只显示匹配的联系人信息
- 不允许添加重复联系人信息(一名联系人可以有多个电话)
- 未选中报表视图中联系人时修改联系人和删除联系人按钮不可用
- 查找联系人时根据关键字进行查找(即输入名字或电话的一部分或者仅选择群组都可以查找到匹配的联系人)
List Control
控件Group Box
控件List Box
控件Edit Control
控件Combo Box
控件Static Text
控件Button
控件通过点击主对话框中的添加联系人和修改联系人按钮分别弹出子对话框。
新建MFC应用程序的过程省略,类型选择基于对话框。(基本操作默认都会,不会的请自行百度)
子对话框可将自带的确认和取消按钮的Caption
属性改成保存和取消即可。
在资源视图中的Dialog插入两个新的对话框作为上述两个子对话框。
通过类向导进行此步操作
1. 类
分别为三个对话框添加类,命名随意即可。MailListtDlg
ContactAdding
ContactModifying
分别为本通讯录的主对话框类、添加联系人子对话框类、修改联系人子对话框类。(右键点击对话框找到添加类)
2. 成员变量
命名随意即可。
Combo Box
的控件类别变量和值类别变量,第3、4、5、6项分别为姓名框和电话框Edit Control
的控件类别变量和值类别变量,第7项为备注框List Box
的控件类别变量,第8项为报表视图List Control
的控件类别变量。Combo Box
的控件类别变量和值类别变量,第3、4、5项分别为姓名框、电话框、备注框Edit Control
的值类别变量。3. 命令
主对话框的命令
所有Button
控件添加单击响应函数BN_CLICKED
,List Control
控件添加消息NM_CLICK
DBLCLK
。
子对话框的命令
所有Button
控件添加单击响应函数BN_CLICKED
。(若是将对话框自带的确认和取消按钮的Caption
属性改成保存和取消则不用进行此项操作)
4. 虚函数
只需为两个子对话框各自添加一个初始化函数OnInitDialog
。
以下代码的类名请根据自己之前的命名进行修改,对象名的命名随意。不懂的函数自行百度(我都是百度看懂的)。代码的顺序按功能的构思思路进行安排。
1. 添加一个类存储联系人各项信息
新建一个头文件将此类写进去,在需要用到此类的cpp文件中include此头文件。
class MyClass {
public:
//姓名,5个字内
char Name[12];
//电话,11个数字
char Phone[13];
//群组
char Group[10];
//群组索引(因为群组是ComboxBox控件,所以需要索引)
//初始化-1是为了当通讯录没有数据进行保存时不会错误将数据写入文件)
int Group_Index = -1;
//备注,50个字以内
char Remark[104];
};
2、添加全局变量统计联系人人数和存储各个联系人
stdafx.h
//统计联系人人数
extern int N;
//存储各个联系人
extern MyClass new_people[100];
-----------------------------------------------------------------------
stdafx.cpp
int N = 0;
MyClass new_people[100];
3、主对话框的初始化函数
实现读取保存联系人信息功能。在头文件中进行read函数的声明,在实现文件中进行read函数的定义;read函数用于读入文件中已有的联系人信息,初始化函数用读入的联系人信息进行初始化主对话框,在报表视图中显示联系人信息。
MailListtDlg.h
void read();
-----------------------------------------------------------------------
MailListtDlg.cpp
void CMailListtDlg::Read(){
CStdioFile file;
CString str;
file.Open("test.txt", CFile::modeRead);
int now = 0;
while (file.ReadString(str) != NULL){
int i;
if (now == 0) {
N++;
for (i = 0; i < str.GetLength(); i++) {
new_people[N - 1].Name[i] = str[i];
}
new_people[N-1].Name[str.GetLength()] = '\0';
}
else if (now == 1) {
for (i = 0; i < str.GetLength(); i++) {
new_people[N-1].Phone[i] = str[i];
}
new_people[N-1].Phone[str.GetLength()] = '\0';
}
else if (now == 2) {
strcpy_s(new_people[N-1].Group, str);
}
else if (now == 3) {
new_people[N - 1].Group_Index = _ttoi(str);
}
else if (now == 4) {
for (i = 0; i < str.GetLength(); i++) {
new_people[N - 1].Remark[i] = str[i];
}
new_people[N-1].Remark[str.GetLength()] = '\0';
}
now++;
now %= 5;
}
}
BOOL CMailListtDlg::OnInitDialog(){
CDialogEx::OnInitDialog();
//初始化时读取文件内容,自定义的Read函数读取文件
CMailListtDlg Read;
Read.Read();
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
//设置报表视图的头标题
CRect rect;
CListCtrl* pmyListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST4);
LONG dwStyle = GetWindowLong(pmyListCtrl->m_hWnd, GWL_STYLE);
SetWindowLong(pmyListCtrl->m_hWnd, GWL_STYLE, dwStyle | LVS_REPORT);
LONG styles = pmyListCtrl->GetExtendedStyle();
pmyListCtrl->SetExtendedStyle(styles | LVS_EX_FULLROWSELECT |LVS_EX_GRIDLINES | LVS_NOSCROLL);
pmyListCtrl->GetWindowRect(&rect);
pmyListCtrl->InsertColumn(0, "姓名", LVCFMT_CENTER, rect.Width() / 3);
pmyListCtrl->InsertColumn(1, "电话", LVCFMT_CENTER, rect.Width() / 3);
pmyListCtrl->InsertColumn(2, "群组", LVCFMT_CENTER, rect.Width() / 3);
//当导入了联系人信息且联系人信息非空时,报表视图按文本中联系人信息顺序显示
int nlist = m_ListCtrl.GetItemCount();
if (new_people[0].Group_Index != -1) {
CString str;
for (int i = N - 1; i >= 0; i--) {
str.Format("%s", new_people[i].Name);
m_ListCtrl.InsertItem(nlist, str);
str.Format("%s", new_people[i].Phone);
m_ListCtrl.SetItemText(nlist, 1, str);
str.Format("%s", new_people[i].Group);
m_ListCtrl.SetItemText(nlist, 2, str);
}
}
//Combo Box控件显示内容
m_zhuGroup.AddString(_T(""));
m_zhuGroup.AddString(_T("无"));
m_zhuGroup.AddString(_T("家人"));
m_zhuGroup.AddString(_T("朋友"));
m_zhuGroup.AddString(_T("同学"));
m_zhuGroup.SetCurSel(0);
//修改和删除联系人按钮灰显
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
return TRUE;
}
4. 单击“添加联系人”按钮的响应函数
void CMailListtDlg::OnBnClickedButton1() {
ContactAdding dlg;
//弹出添加联系人子对话框,当子对话框通过保存键关闭时,进行if内的操作
if (IDOK == dlg.DoModal()) {
//添加联系人到报表视图 并存储到全局变量
//获取当前报表视图的行数
int i;
CString str;
int nHeadNum = m_ListCtrl.GetItemCount();
//姓名
str = dlg.m_Name2;
str.TrimLeft();
str.TrimRight();
//报表视图中插入姓名
m_ListCtrl.InsertItem(nHeadNum, str);
//将姓名存储到全局变量
for (i = 0; i < str.GetLength(); i++){
new_people[N].Name[i] = str[i];
}
new_people[N].Name[str.GetLength()] = '\0';
//电话
str = dlg.m_Phone2;
//报表视图中插入电话
m_ListCtrl.SetItemText(nHeadNum, 1, str);
//将电话存储到全局变量
for (i = 0; i < 11; i++){
new_people[N].Phone[i] = str[i];
}
new_people[N].Phone[11] = '\0';
//将群组索引存储到全局变量
new_people[N].Group_Index = dlg.Group_Index;
//将群组存储到全局变量
m_zhuGroup.GetLBText(new_people[N].Group_Index + 1, new_people[N].Group);
//报表视图插入群组
m_ListCtrl.SetItemText(nHeadNum, 2, new_people[N].Group);
//备注
str = dlg.m_Variable2;
str.TrimLeft();
str.TrimRight();
//将备注存储到全局变量
for (i = 0; i < str.GetLength(); i++){
new_people[N].Remark[i] = str[i];
}
new_people[N].Remark[str.GetLength()] = '\0';
//联系人人数+1
N++;
}
}
BOOL ContactAdding::OnInitDialog()
{
CDialogEx::OnInitDialog();
//Combo Box控件显示“无”,并有另外三项选择
m_ComboBox.AddString(_T("无"));
m_ComboBox.AddString(_T("家人"));
m_ComboBox.AddString(_T("朋友"));
m_ComboBox.AddString(_T("同学"));
m_ComboBox.SetCurSel(0);
return TRUE;
}
void ContactAdding::OnBnClickedOk()
{
//将控件的值赋给成员变量
UpdateData(TRUE);
//判断电话号码是否为11位,若不为11位,报错
if (m_Phone2.GetLength() != 11) {
MessageBox("请输入11位的电话号码");
}
//若电话号码为11位
else{
//check函数判断是否存在重复电话号码,可以重复联系人姓名
if (check() == 1) {
m_Name2.TrimLeft();
m_Name2.TrimRight();
//名字不能为空
if (m_Name2.IsEmpty()) {
MessageBox("添加联系人信息不能为空");
}
//将群组ComboBox索引赋给该类的变量,将在关闭子对话框后使用
else {
Group_Index = m_ComboBox.GetCurSel();
CDialog::OnOK();
}
}
//check函数判断有重复电话号码
else {
MessageBox("请不要添加重复的联系人信息");
}
}
}
ContactAdding.h
中声明check函数。联系人电话不可以重复,可以一人多号。ContactAdding.h
int check();
------------------------------------------------------------------------------------------
ContactAdding.cpp
int ContactAdding::check() {
char Phone[13];
//类型转换
for (int i = 0; i < m_Phone2.GetLength(); i++)
{
Phone[i] = m_Phone2[i];
}
Phone[m_Phone2.GetLength()] = '\0';
//字符通过循环判断是否相同,不能用==判断
for (int i = 0; i < N; i++) {
for (int j = 0; j < 11; j++) {
//存在数字不相等即电话号码不相等,跳出该电话的循环
if (Phone[j] != new_people[i].Phone[j])
break;
//若循环进行到第十一数字,第十一个数字也相等,即该存在相同号码
if (j == 10 && Phone[j] == new_people[i].Phone[j])
//打断循环并返回函数值
return 0;
}
}
//若循环进行完全,即不存在相同号码
return 1;
}
5. 单击“删除联系人”按钮的响应函数
删除联系人后相应会更新全局变量
void CMailListtDlg::OnBnClickedButton2()
{
//当在报表框中选择了一项
while (m_ListCtrl.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED) != -1) {
//获得选中项的索引
int nItem;
nItem = m_ListCtrl.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
//删除报表框中的选择的一行
m_ListCtrl.DeleteItem(nItem);
//更新全局变量信息
for (int i = nItem; i < N; i++) {
strcpy_s(new_people[i].Name, 11,new_people[i + 1].Name);
strcpy_s(new_people[i].Phone, 12, new_people[i + 1].Phone);
strcpy_s(new_people[i].Group, 9, new_people[i + 1].Group);
strcpy_s(new_people[i].Remark, 102, new_people[i + 1].Remark);
new_people[i].Group_Index = new_people[i + 1].Group_Index;
}
//联系人人数减一
N--;
//删除、修改联系人按钮灰显
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
}
//清空备注框(因为选中报表框一项时备注框中会显示该联系人的相应备注)
m_Variable.ResetContent();
}
6、单击“报表视图”中一项的响应函数
备注框会显示选中联系人的备注信息。选中联系人后,修改联系人和删除联系人按钮可以使用。
void CMailListtDlg::OnClickList4(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
DWORD dwPos = GetMessagePos();
CPoint point(LOWORD(dwPos), HIWORD(dwPos));
//查看点击位置
m_ListCtrl.ScreenToClient(&point);
LVHITTESTINFO lvinfo;
lvinfo.pt = point;
lvinfo.flags = LVHT_ABOVE;
int nItem = m_ListCtrl.SubItemHitTest(&lvinfo);
//如果选中了联系人
if (nItem != LB_ERR)
{
//先清空备注框
m_Variable.ResetContent();
//删除,修改按钮可按
GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON3)->EnableWindow(TRUE);
//备注框中显示相应联系人的备注
m_Variable.AddString(new_people[lvinfo.iItem].Remark);
}
//点中了报表框中的空白处
else {
//备注框清空
m_Variable.ResetContent();
//删除,修改联系人按钮灰显
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
}
*pResult = 0;
}
9、单击“修改联系人”按钮的响应函数
在ContactModifying.h
中声明两个int类型的变量,使修改联系人子对话框初始化时群组框能显示选中联系人的群组。
ContactModifying.h
int RecordList;
int RecordGroup_Index
------------------------------------------------------------------------------------------
MailListtDlg.cpp
void CMailListtDlg::OnBnClickedButton3()
{
ContactModifying dlg;
//获得列表框选择的位置
int nlist = m_ListCtrl.GetNextItem(-1, LVNI_SELECTED);
dlg.RecordList = nlist;
dlg.RecordGroup_Index = new_people[nlist].Group_Index;
//类型转换
dlg.m_Name3.Format("%s", new_people[nlist].Name);
dlg.m_Phone3.Format("%s", new_people[nlist].Phone);
dlg.m_Group3.Format("%s", new_people[nlist].Group);
dlg.m_Group_Index3 = new_people[nlist].Group_Index;
dlg.m_Variable3.Format("%s", new_people[nlist].Remark);
//弹出添加联系人子对话框,当子对话框通过保存键关闭时,进行if内的操作
int nIdex = dlg.DoModal();
if (nIdex == IDOK) {
m_Variable.ResetContent();
m_ListCtrl.DeleteItem(nlist);
//全局变量信息更新+报表视图更新
CString str; int i;
//姓名
str = dlg.m_Name3;
str.TrimLeft(); str.TrimRight();
for (i = 0; i < str.GetLength(); i++) {
new_people[nlist].Name[i] = str[i];
}
new_people[nlist].Name[str.GetLength()] = '\0';
//更新报表视图
m_ListCtrl.InsertItem(nlist, str);
// 电话
str = dlg.m_Phone3;
str.TrimLeft(); str.TrimRight();
for (i = 0; i < str.GetLength(); i++) {
new_people[nlist].Phone[i] = str[i];
}
new_people[nlist].Phone[str.GetLength()] = '\0';
//更新报表视图
m_ListCtrl.SetItemText(nlist, 1, str);
// 备注
str = dlg.m_Variable3;
str.TrimLeft(); str.TrimRight();
for (i = 0; i < str.GetLength(); i++) {
new_people[nlist].Remark[i] = str[i];
}
new_people[nlist].Remark[str.GetLength()] = '\0';
// 群组
new_people[nlist].Group_Index = dlg.m_Group_Index3;
if (dlg.m_Group_Index3 == 0)
str = "无";
else if (dlg.m_Group_Index3 == 1)
str = "家人";
else if (dlg.m_Group_Index3 == 2)
str = "朋友";
else if (dlg.m_Group_Index3 == 3)
str = "同学";
for (i = 0; i < str.GetLength(); i++) {
new_people[nlist].Group[i] = str[i];
}
new_people[nlist].Group[str.GetLength()] = '\0';
//更新报表视图
m_ListCtrl.SetItemText(nlist, 2, str);
//删除、修改联系人按钮灰显
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
}
}
BOOL ContactModifying::OnInitDialog()
{
CDialogEx::OnInitDialog();
m_ComboBox3.AddString(_T("无"));
m_ComboBox3.AddString(_T("家人"));
m_ComboBox3.AddString(_T("朋友"));
m_ComboBox3.AddString(_T("同学"));
m_ComboBox3.SetCurSel(RecordGroup_Index);
return TRUE;
}
void ContactModifying::OnBnClickedOk()
{
//将控件的值赋给成员变量
UpdateData(TRUE);
//判断电话号码是否为11位
if (m_Phone3.GetLength() != 11) {
MessageBox("请输入11位的电话号码");
}
//若电话号码为11位
else {
//check函数判断重复信息(和添加联系人的check函数不一样)
if (check() == 1) {
m_Name3.TrimLeft();
m_Name3.TrimRight();
//名字不能为空
if (m_Name3.IsEmpty()) {
MessageBox("添加联系人信息不能为空");
}
//将群组ComboBox索引赋给该类的变量,将在关闭子对话框后使用
else {
m_Group_Index3 = m_ComboBox3.GetCurSel();
CDialog::OnOK();
}
}
//check函数判断有重复电话号码
else {
MessageBox("请不要添加重复的联系人信息");
}
}
}
ContactModifying.h
中声明check函数。在修改联系人的过程中,存在只修改备注,不修改其他信息的情况,若使用添加联系人的check函数,会出现错误的报错。ContactModifying.h
int check();
------------------------------------------------------------------------------------------
ContactModifying.cpp
int ContactModifying::check() {
//类型转换
//姓名
char Name[12];
for (int i = 0; i < m_Name3.GetLength(); i++)
{
Name[i] = m_Name3[i];
}
Name[m_Name3.GetLength()] = '\0';
//电话
char Phone[13];
for (int i = 0; i < m_Phone3.GetLength(); i++)
{
Phone[i] = m_Phone3[i];
}
Phone[m_Phone3.GetLength()] = '\0';
//当m=0时,即修改的电话和选中联系人的电话相同;当m=1时,则不相同
int m = 0;
for (int i = 0; i < 11; i++) {
if (Phone[i] != new_people[RecordList].Phone[i]) {
m = 1;
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < 11; j++) {
//一个数字不相等即电话号码不相等,跳出该电话的循环
if (Phone[j] != new_people[i].Phone[j])
break;
//若循环进行到第十一数字,第十一个数字也相等,即该存在相同号码
//m==1即相同号码不为选中联系人电话,判断为真实存在重复电话
if (j == 10 && Phone[j] == new_people[i].Phone[j] && m == 1)
return 0;
}
}
//若循环进行完全,即不存在相同号码
return 1;
}
8、双击“报表视图”中一项的响应函数
和单击“修改联系人”按钮的响应函数相同。
9、单击“查找”按钮的响应函数
void CMailListtDlg::OnClickedButton5()
{
//将控件值传给成员变量
UpdateData(TRUE);
//声明定义一个MyClass对象存储信息
MyClass Find;
CString str;
//类型转换
//姓名
str = m_Name1;
str.TrimLeft();
str.TrimRight();
for (int i = 0; i < str.GetLength(); i++)
Find.Name[i] = str[i];
Find.Name[str.GetLength()] = '\0';
//电话
str = m_Phone1;
str.TrimLeft();
str.TrimRight();
for (int i = 0; i < str.GetLength(); i++)
Find.Phone[i] = str[i];
Find.Phone[str.GetLength()] = '\0';
//索引
//主对话框中的Combo Box索引数比其他子对话框的索引数多一个,因为主对话框中的ComboBox默认不显示,所以要-1
Find.Group_Index = m_zhuGroup.GetCurSel() - 1;
CString s1, s2;
CString check;
int Record[100];
int record = 0;
int que[100];
for (int i = 0; i < 100; i++) {
que[i] = i;
}
for (int i = 0; i < N; i++) {
//类型转换
s1.Format("%s", Find.Name);
s2.Format("%s", Find.Phone);
//如果输入查找的群组和当前循环的群组不一样,则进行下一次循环
//自己也没想懂逻辑
if ((new_people[i].Group_Index == -1) || (Find.Group_Index != -1 && Find.Group_Index != new_people[i].Group_Index) || (Find.Group_Index == -1 && new_people[i].Group_Index != -1 && s1.IsEmpty() && s2.IsEmpty()))
continue;
//如果当前循环的姓名不存在输入查找的姓名或姓名的一部分,则进行下一次循环
s1.Format("%s", Find.Name);
s2.Format("%s", new_people[i].Name);
if (!s1.IsEmpty() && s2.Find(s1) == -1)
continue;
//如果当前循环的电话不存在输入查找的电话或电话的一部分,则进行下一次循环
s1.Format("%s", Find.Phone);
s2.Format("%s", new_people[i].Phone);
if (!s1.IsEmpty() && s2.Find(s1) == -1)
continue;
Record[que[record]] = i;
record ++;
}
//弹窗显示查找到多少名联系人
check.Format("共查到%d条联系人", record);
MessageBox(check);
//如果找到匹配联系人,清空报表视图,只显示匹配联系人信息
if (record > 0) {
m_ListCtrl.DeleteAllItems();
for (int i = 0; i < record; i++) {
m_ListCtrl.InsertItem(i, new_people[Record[que[i]]].Name);
m_ListCtrl.SetItemText(i, 1, new_people[Record[que[i]]].Phone);
m_ListCtrl.SetItemText(i, 2, new_people[Record[que[i]]].Group);
}
}
}
10、单击“显示全部”按钮的响应函数
void CMailListtDlg::OnClickedButton6()
{
//清空报表视图,因为查找后只显示匹配联系人信息
m_ListCtrl.DeleteAllItems();
//清空查找框中输入的信息
m_Name11.SetWindowTextA("");
m_Phone11.SetWindowTextA("");
m_zhuGroup.SetCurSel(0);
//报表视图显示所有联系人信息,提取全局变量
for (int i = 0; i < N; i++) {
m_ListCtrl.InsertItem(i, new_people[i].Name);
m_ListCtrl.SetItemText(i, 1, new_people[i].Phone);
m_ListCtrl.SetItemText(i, 2, new_people[i].Group);
}
}
11、单击“保存”按钮的响应函数
将全局变量中的联系人信息写出文件保存,并用于下次读入。
void CMailListtDlg::OnBnClickedButton7()
{
CStdioFile file;
file.Open("test.txt", CFile::modeCreate | CFile::modeWrite);
CString str;
if (new_people[0].Group_Index != -1) {
for (int i = 0; i < N; i++) {
//姓名
str.Format("%s\n", new_people[i].Name);
file.WriteString(str);
//电话
str.Format("%s\n", new_people[i].Phone);
file.WriteString(str);
//群组
str.Format("%s\n", new_people[i].Group);
file.WriteString(str);
//群组索引
str.Format("%d\n", new_people[i].Group_Index);
file.WriteString(str);
//备注
str.Format("%s\n", new_people[i].Remark);
file.WriteString(str);
}
}
MessageBox("保存成功");
CDialogEx::OnCancel();
}