週一晚上十點整!! 完工了, 從上週五晚上做到現在。
先上一個最終效果圖:
12-19週二下午更新(修復了兩個bug) 一個是修改的時候隊列位置的錯位問題, 一個是備註信息顯示錯亂的問題。
另外做了一個應用的圖標。
首先說說一下總結, 雖然整個程序做完了, 但是還是有很多缺陷, 比如寫了很多沒有用的代碼。 因爲很多地方都不會, 直接去百度, 找到一個解決的辦法就用了, 實際上會有更優的辦法。 還有就是對於類的理解不夠深刻, 很多想實現的東西還是用競賽代碼的思想去實現, 真正的工程代碼肯定不會是我這種代碼的格式。
之前從來沒接觸過工程,遇到了很多問題, 所以邊做邊記錄。 做的過程中遇到的問題我基本都寫在了裏面並附有解決方法和參考的博客鏈接, 我想許多第一次寫mfc的人應該也會遇到同樣的問題, 所以應該會有一些幫助吧。 僅供參考, 沒辦法作爲教程, 寫的很散亂, 步驟可能也很跳躍。 畢竟是兩者同時進行的時候, 寫代碼爲主, 寫博客爲輔。
工程是週五晚開始做的, 這個記錄是週六上午開始寫的, 所以剛開始就沒什麼記錄。 之後都是解決一個問題寫一點記錄一點, 會比較詳細。
週五晚上弄了一下基本框架。 我用的是純對話框做的。 我也不知道正確的順序是啥, 一點點來吧。 首先是框架。
添加聯繫人框架
然後開始搞主框架, 首先解決的左邊信息的顯示問題, 剛開始我用的是列邊框, 也就是listbox
, 其實是錯的, 應該用列表控件 listctrl。
這纔是我想要的, 能夠顯示信息。
緊接着是解決列表控件的初始化問題, 就是想要實現打開程序後, 通訊錄的自動加載以及上面的分欄。
- 解決分欄問題:在OnInitDialog()函數中添加代碼:
CListCtrl* pmyListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_TOT); //獲取列表控件
DWORD dwStyle = GetWindowLong(pmyListCtrl->m_hWnd, GWL_STYLE);
SetWindowLong( pmyListCtrl->m_hWnd, GWL_STYLE, dwStyle | LVS_REPORT);
DWORD styles = pmyListCtrl->GetExtendedStyle();
pmyListCtrl->SetExtendedStyle(styles|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);//設置listctrl可以整行選擇和網格條紋
CRect rect;
pmyListCtrl->GetWindowRect(&rect);
m_list.InsertColumn(0,"姓名",LVCFMT_CENTER,rect.Width()/6);//設置標題
m_list.InsertColumn(1,"電話",LVCFMT_CENTER,rect.Width()/6*2);
m_list.InsertColumn(2,"郵箱",LVCFMT_CENTER,rect.Width()/6*2);
m_list.InsertColumn(3,"分組",LVCFMT_CENTER,rect.Width()/6);
z這樣列表的設置問題就解決了, 發現了一個博客, 裏面寫的很詳細, listctrl總結。 順便搞了一下在控制窗口的輸出。最後用讀文件應該也是用這種方法顯示。
int nRow = m_list.InsertItem(0, "嚴嘉豪");// 插入行
m_list.InsertItem(1, "譚瑞");// 插入行
m_list.InsertItem(2, "馬博");
m_list.SetItemText(nRow, 1, "110");// 設置其它列數據
m_list.SetItemText(nRow, 2, "87*****@qq.om");
m_list.SetItemText(nRow, 3, "無");
剛剛發現自己新建的窗口不對, 昨天創建的是非模式對話框(多個窗口是活動的), 但是我是想創建模式對話框(只有當前窗口是活動的)。
完全刪除類的方法:
MFC Wizard中創建的類用類嚮導刪除後並不能刪除源文件,可以通過以下簡單的幾步完全刪除:
1:從workspace中的fileview中刪除對應的.h和.cpp文件。
2.再關閉項目,從實際的文件夾中刪除對應的.h和.cpp文件。
3.再刪除.clw文件。
再打開重新編譯即可!
重新解決了添加按鈕的對話框模式, 首先在資源視圖的Dialog右鍵添加Dialog, 新建的窗口自己命名並且設置ID, 利用class wizard 自動添加類, 在主窗口#include”ADD.h” 包含文件, 在添加按鈕中加入代碼
void CZbookDlg::OnButtonAdd()
{
ADD dlg;
dlg.DoModal();
// TODO: Add your control notification handler code here
}
實現點擊添加聯繫人按鈕打開新的添加窗口。忙活了半天, 基本上是把昨晚上做的翻工了一遍。。。
半個小時又過去了, 基本的框架都已經想好了。主界面大概是這個樣子:
有兩個子窗口, 一個是添加聯繫人窗口, 一個是修改聯繫人窗口, 並且這兩個窗口的佈局基本相同。
機房吹空調好乾啊。。 出去買點喝的透透氣,回來繼續寫。
解決了分組下拉欄問題。 在裏面添加了5個分組:全部、無、家人、同事、朋友。
方法是右鍵打開組合框(下拉欄)屬性, 在,在數據欄添加初始數據, 用ctrl +enter換行, 取消分類, 不然系統會自動排序。 然後在initDialog() 函數初始化默認選項, 因爲我把全部排在第一個, 所以下標是0。 添加代碼
m_Flist.SetCurSel(0);//初始化分組選擇下拉欄的默認選項。
效果如下
同理, 給添加聯繫人窗口和修改聯繫人窗口的下拉欄也初始化, 當然要注意的是, 沒有了全部分組, 因爲全部分組是查找的時候用的。
對於添加對話框的初始化函數, 需要用class wizard 來添加。 詳見這裏
因爲刪除函數需要讀取選中的信息,現在我還沒有初始化, 先不動修改和刪除這兩個模塊。
CString strtemp;
//strtemp.Format("單擊的是第%d行第%d列", lvinfo.iItem, lvinfo.iSubItem);
strtemp.Format("bababalalal");
用來測試程序用的彈窗代碼。
實現:在主窗口, 當沒有選擇聯繫人的時候, 無法點擊刪除和修改按鈕, 當選中聯繫人後, 按鈕可以點擊。
效果:
。
添加方法:
首先給listctrl添加NM_CLICK消息函數(用class wizard) 在對應的函數裏編輯:
DWORD dwPos = GetMessagePos();//通過查看點擊位置 確定修改和刪除按鈕是否可點。
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
m_list.ScreenToClient(&point);
LVHITTESTINFO lvinfo;
lvinfo.pt = point;
lvinfo.flags = LVHT_ABOVE;
int nItem = m_list.SubItemHitTest(&lvinfo);
if(nItem != -1)// 選擇了聯繫人
{
GetDlgItem(IDC_BUTTON_DEL)-> EnableWindow(TRUE);// 刪除窗口可以點擊 (傳入的是按鈕控件的ID)
GetDlgItem(IDC_BUTTON_CHANGE)-> EnableWindow(TRUE); 修改按鈕
}
else{// 沒有選擇聯繫人, 兩個按鈕變灰(不可按)
GetDlgItem(IDC_BUTTON_DEL)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CHANGE)-> EnableWindow(FALSE);
}
listctrl 總結網站: CListCtrl控件使用方法總結
今天到這了, 晚上要打cf, 估計寫不了了。
晚上一直在想數據到底該如何存放以及如何訪問, 第一個問題是在add子窗口添加完信息後, 主窗口如何得到子窗口的變量以及如何在listctrl上顯示出來, 發現一個人寫的程序跟我的思路極其相似並且遇到了同樣的問題, 如何實現MFC主對話框和子對話框之間數據的傳遞。 明天去機房試試。
還有一個博客, 寫到很多方法, 全局變量啊什麼的, 沒有上一個理解的透徹, 先存着。 MFC不同對話框使用公共數據的幾種方法。
小知識點:
UpdateData(TRUE)是將控件的狀態傳給其關聯的變量,當然你要爲控件關聯上變量纔行。
UpdateData(FALSE)是將控件的關聯變量的值傳給控件並改變控件狀態。
UpdateData刷新的是當前對話框。
UpdateData(true);//用於將屏幕上控件中的數據交換到變量中。
UpdateData(false);//用於將數據在屏幕中對應控件中顯示出來。
剛剛看了一下數據傳輸, 突然懂了點什麼, 感覺解決了添加和修改的問題。 看的是這個博客mfc對話框傳遞數據。
數據傳遞分兩類。
1. 父窗口傳到子窗口。
2. 子窗口傳到父窗口。
對於我的程序來說, 添加按鈕需要的是子窗口傳到父窗口。 修改按鈕兩個都需要, (首先通過父傳子獲得需要修改的信息方便顯示, 然後再將修改之後的傳回來)。 應該這樣。
每一次修改/刪除/添加 都需要更新listctrl 並且保存到文件?? 應該是這樣吧, 這一部分還沒想好, 具體的明天再百度一下。
睡覺, 明天白天繼續趕工。
今天是周天。
早晨解決了add子窗口向主窗口傳值的問題, 首先是在主窗口的添加按鈕中添加函數。
void CZbookDlg::OnButtonAdd()
{
ADD dlg;
if(IDOK == dlg.DoModal()){
Myclass new_people;// 如果激活子窗口, 獲取相關信息
new_people.Name = dlg.m_Aname;
new_people.Number = dlg.m_Atel;
new_people.E_mail = dlg.m_Amail;
new_people.Information = dlg.m_Ainfo;
new_people.group_index = dlg.addgroup_index;
/*
CString check; //檢查數據獲取
check.Format("%d", new_people.group_index);
MessageBox(check);
*/
}
// TODO: Add your control notification handler code here
}
如果子窗口正常關閉, 則獲取子窗口中輸入的信息。 然後是在子窗口的卻定按鈕中添加函數。
void ADD::OnAdd()
{
UpdateData(TRUE);
Myclass st;
if(m_Aname.IsEmpty()||m_Atel.IsEmpty()||m_Amail.IsEmpty()){
MessageBox("添加聯繫人信息不能爲空");
}
else{
addgroup_index = m_addgroup.GetCurSel();
CDialog::OnOK();
}
// TODO: Add your control notification handler code here
}
判斷聯繫人是否爲空, 如果不爲空 正常關閉對話框。 我新建了一個變量addgroup_index
是爲了獲取分組的下標, 我想以下標的形式在數據間傳遞,而不是字符串, 但是直接在主窗口的部分好像沒有辦法獲取, 所以我直接在子窗口中添加了一個變量, 然後間接地獲取這個下標。
通過調用listctrl的函數, 現在已經能夠在列表顯示添加內容了。爲了方便數據的共享, 我開了一個全局數組用來存放所有人的信息。 具體方法是在 stdAfx.h
中聲明爲 extern
類型, 然後在 stdAfx.cpp
中初始化。 就成爲全局變量了。 當然別忘了掛上 #include "Myclass.h"
stdAfx.h:
extern int m_tot;// 總人數
extern Myclass People[1005]; 每個人的信息
stdAfx.cpp:
int m_tot;
Myclass People[1005];
現在我的 添加按鈕函數是這樣的:
void CZbookDlg::OnButtonAdd()
{
ADD dlg;
if(IDOK == dlg.DoModal()){
m_tot++;
People[m_tot].Name = dlg.m_Aname;
People[m_tot].Number = dlg.m_Atel;
People[m_tot].E_mail = dlg.m_Amail;
People[m_tot].Information = dlg.m_Ainfo;
People[m_tot].group_index = dlg.addgroup_index;
m_Flist.GetLBText(People[m_tot].group_index+1, People[m_tot].Group); // 爲了顯示分組
/*
CString check; //檢查數據獲取
check.Format("%d", new_people.group_index);
MessageBox(check);
*/
int nHeadNum = m_list.GetItemCount();//獲取當前行數
m_list.InsertItem(nHeadNum, People[m_tot].Name);
m_list.SetItemText(nHeadNum, 1, People[m_tot].Number);
m_list.SetItemText(nHeadNum, 2, People[m_tot].E_mail);
m_list.SetItemText(nHeadNum, 3, People[m_tot].Group);
//m_Info.SetWindowText(new_people.Information);
}
// TODO: Add your control notification handler code here
}
目前效果是這樣:
接下來想要實現的是在主窗口選中一個人後, 下面備註會顯示相關信息,並且是隻讀屬性, 無法修改。
首先修改只讀屬性, 在編輯框直接右鍵 屬性, 只讀。
然後在listctrl的 click
函數中添加兩行代碼
m_Info.SetWindowText(People[lvinfo.iItem+1].Information);// 在備註欄顯示相關信息
UpdateData(FALSE); // 更新編輯框
剛剛突然發現一個問題, 就是下拉欄的類型應該設置爲下拉列表, 才能保證是選擇框, 不然的話會變成可選擇的編輯框了。
12點了 一上午又過去了。
發現一個需要修改的地方, 就是備註的編輯框, 需要設置成自動換行 方法:
1.新建一個編輯框控件(Edit Control),將其多行(Multiline)前面打勾(屬性設置爲True),Auto HScroll前面的勾去掉(屬性設置False),這樣就可以實現每一行填滿後自動換行了。
2.再將垂直滾動條(Vetrical Scroll)前面打勾(屬性設置爲True),當輸入或顯示超過編輯框的大小後就會出現垂直滾動條。
改了一些字符串的東西: 定義的全局變量要用char 數組, 不能用CString 不然的話後面存到文件裏很難弄, 改成char之後, 就要處理Cstring 轉char 和讀入空格的問題, 用
a.TrimLeft();a.TrimRight(); 可以消除CString類型 左右的空格, 中間的消不掉。
首先重新修改了添加聯繫人判空的方法: 在ADD窗口的add按鍵中, 先取出每個編輯框的字符串, 然後去除左右的空格, 如果爲空則爲非法輸入, 需要彈窗提示。
void ADD::OnAdd()
{
UpdateData(TRUE);
bool flag = true;
CString str;
str = m_Aname; // 處理空信息
str.TrimLeft(); str.TrimRight();
if(str.IsEmpty()) flag = false;
str = m_Atel;
str.TrimLeft(); str.TrimRight();
if(str.IsEmpty()) flag = false;
str= m_Amail;
str.TrimLeft(); str.TrimRight();
if(str.IsEmpty()) flag = false;
if(!flag) { MessageBox("添加聯繫人信息不能爲空"); }
else{
addgroup_index = m_addgroup.GetCurSel();
CDialog::OnOK();
}
// TODO: Add your control notification handler code here
}
如果輸入合法, 則需要把相關信息放到數組中, 具體方法是在主窗口的添加 按鈕處理。
void CZbookDlg::OnButtonAdd()
{
ADD dlg;
if(IDOK == dlg.DoModal()){
m_tot++;
int i;
CString str;
int nHeadNum = m_list.GetItemCount();//獲取當前行數 添加聯繫人到列表
str = dlg.m_Aname;//姓名
str.TrimLeft(); str.TrimRight();
m_list.InsertItem(nHeadNum, str);
for(i = 0; i < str.GetLength(); i++) People[m_tot].Name[i] = str[i];
People[m_tot].Name[str.GetLength()] = '\0';
str = dlg.m_Atel;//電話
str.TrimLeft(); str.TrimRight();
m_list.SetItemText(nHeadNum, 1, str);
for(i = 0; i < str.GetLength(); i++) People[m_tot].Number[i] = str[i];
People[m_tot].Number[str.GetLength()] = '\0';
str = dlg.m_Amail;//郵箱
str.TrimLeft(); str.TrimRight();
m_list.SetItemText(nHeadNum, 2, str);
for(i = 0; i < str.GetLength(); i++) People[m_tot].E_mail[i] = str[i];
People[m_tot].E_mail[str.GetLength()] = '\0';
str = dlg.m_Ainfo;//備註
for(i = 0; i < str.GetLength(); i++) People[m_tot].Information[i] = str[i];
People[m_tot].Information[str.GetLength()] = '\0';
People[m_tot].group_index = dlg.addgroup_index;// 分組
m_Flist.GetLBText(People[m_tot].group_index+1, People[m_tot].Group); // 爲了顯示分組
m_list.SetItemText(nHeadNum, 3, People[m_tot].Group);
/*
CString check; //檢查數據獲取
check.Format("%d", new_people.group_index);
MessageBox(check);
*/
}
// TODO: Add your control notification handler code here
}
暫時添加模塊沒有問題了, 開始搞刪除模塊。
首先還是用 class wizard
給del按鈕添加click消息函數,
思路: 首先要選中一個列表聯繫人, 然後刪除框纔可以點擊, 把電機的行數傳給刪除窗口, 再改變數組。
百度了一下, 發現一個函數可以很智能的刪除列表選中的選項, 並且返回行數, 這樣即解決了列表的刪除, 也能解決數組中刪除。
參考的博客: CListCtrl刪除選中行。 我用的是方法三。
代碼如下:
void CZbookDlg::OnButtonDel()
{
CString check;
int nItem;
// TODO: Add your control notification handler code here
while(m_list.GetNextItem(-1,LVNI_ALL | LVNI_SELECTED) != -1){
nItem = m_list.GetNextItem(-1,LVNI_ALL | LVNI_SELECTED);
m_list.DeleteItem(nItem);
int pos = nItem + 1;
for(int i = pos; i < m_tot; i++){
strcpy(People[i].Name, People[i+1].Name);
strcpy(People[i].Number, People[i+1].Number);
strcpy(People[i].E_mail, People[i+1].E_mail);
strcpy(People[i].Information, People[i+1].Information);
People[i].group_index = People[i+1].group_index;
}
m_t
}
/*
check.Format("%d", nItem);
MessageBox(check);
*/
ot--;
//因爲點擊了一下修改按鈕之後, 列表的選擇就沒了, 我想讓修改和查詢按鈕再次不可點。 所以再加兩句代碼。
}
這樣刪除功能基本實現了, 開始搞修改功能。
修改功能首先要做的就是選中列表欄信息後, 點擊刪除, 會把相應的信息讀入到刪除窗口中, 這個問題弄了好一會。
首先是在主窗口的刪除按鈕添加代碼:
void CZbookDlg::OnButtonChange()
{
Mod dlg;
int nlist = m_list.GetNextItem(-1, LVNI_SELECTED)+1; //獲得列表框選擇的位置
dlg.m_Mname.Format("%s", People[nlist].Name);
dlg.m_Mtel.Format("%s", People[nlist].Number);
dlg.m_Mmail.Format("%s", People[nlist].E_mail);
dlg.m_Minfo.Format("%s", People[nlist].Information);
dlg.m_Mgroup_index = People[nlist].group_index;
dlg.DoModal();
GetDlgItem(IDC_BUTTON_DEL)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CHANGE)-> EnableWindow(FALSE);
}
這樣就把除了分組之外的信息都傳到了刪除窗口裏, 爲什麼是除了分組信息呢, 因爲分組是個下拉欄, 我在刪除類裏新建了一個變量 m_Mgroup_index
記錄對應的標號, 在刪除模塊中添加init預處理函數, 在預處理函數中才能修改下拉欄默認輸出項, 否則會一直程序出錯。
BOOL Mod::OnInitDialog()
{
CDialog::OnInitDialog();
m_Mgroup.SetCurSel(m_Mgroup_index);//初始化分組選擇下拉欄的默認選項。 一定要寫下主窗口初始化的下面。
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
實現了修改功能, 基本上和添加很相似, 唯一不一樣的就是要在列表框先刪除當前這一行的信息, 然後再重新寫入。
和添加的函數基本雷同
void CZbookDlg::OnButtonChange()
{
Mod dlg;
int nlist = m_list.GetNextItem(-1, LVNI_SELECTED); //獲得列表框選擇的位置
dlg.m_Mname.Format("%s", People[nlist].Name);
dlg.m_Mtel.Format("%s", People[nlist].Number);
dlg.m_Mmail.Format("%s", People[nlist].E_mail);
dlg.m_Minfo.Format("%s", People[nlist].Information);
dlg.m_Mgroup_index = People[nlist].group_index;
if(IDOK == dlg.DoModal()){
m_list.DeleteItem(nlist);
CString str; int i;
str = dlg.m_Mname;//姓名
str.TrimLeft(); str.TrimRight();
m_list.InsertItem(nlist, str);
for(i = 0; i < str.GetLength(); i++) People[nlist].Name[i] = str[i];
People[nlist].Name[str.GetLength()] = '\0';
str = dlg.m_Mtel;// 電話
str.TrimLeft(); str.TrimRight();
m_list.SetItemText(nlist, 1, str);
for(i = 0; i < str.GetLength(); i++) People[nlist].Number[i] = str[i];
People[nlist].Number[str.GetLength()] = '\0';
str = dlg.m_Mmail;// 電話
str.TrimLeft(); str.TrimRight();
m_list.SetItemText(nlist, 2, str);
for(i = 0; i < str.GetLength(); i++) People[nlist].E_mail[i] = str[i];
People[nlist].E_mail[str.GetLength()] = '\0';
str = dlg.m_Minfo;// 備註
str.TrimLeft(); str.TrimRight();
for(i = 0; i < str.GetLength(); i++) People[nlist].Information[i] = str[i];
People[nlist].Information[str.GetLength()] = '\0';
People[nlist].group_index = dlg.m_Mgroup_index;// 分組
if(dlg.m_Mgroup_index == 0) str = "無";
else if(dlg.m_Mgroup_index == 1) str = "家人";
else if(dlg.m_Mgroup_index == 2) str = "同事";
else if(dlg.m_Mgroup_index == 3) str = "朋友";
for(i = 0; i < str.GetLength(); i++) People[nlist].Group[i] = str[i];
People[nlist].Group[str.GetLength()] = '\0';
m_list.SetItemText(nlist, 3, str);
}
GetDlgItem(IDC_BUTTON_DEL)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CHANGE)-> EnableWindow(FALSE);
}
Demo:
現在基本完成了三大操作, 添加 修改 刪除。
還沒有實現的:
1. 新建的時候判斷當前電話是否已經存在, 若存在, 則不能添加。
2. 文件的讀寫保存。
3. 查詢功能。
1問題解決, 一個check函數的問題, O(n)檢查一遍就可以。 我在Myclass累裏寫了一個checkIn函數, 然後調用People[0].checkIn。
我決定先搞查詢。。 最後在弄文件。
就在我決定去解決查詢問題的時候,忽然發現一個細節(bug) 就是如果在修改聯繫人的時候修改出一個之前已經存在的電話, 也需要check一下。 所以在修改部分也需要添加checkIn函數。
花了好長時間, 解決了查找的第一部分問題, 最簡單的查找, 首先是允許查找的情況 只要不是姓名空&& 電話空&& (分組==全部)都可以查找, 查找的時候, 就是一些判斷, 我開了一個全局的數組模擬隊列把符合的下標都存起來並記錄總個數。
代碼:
void CZbookDlg::OnButtonFind()
{
UpdateData(TRUE);
Myclass Sfind;
CString str; int i;
bool ok1 = false, ok2 = false, ok3 = false;
str = m_Fname;
str.TrimLeft(); str.TrimRight();
for(i = 0; i < str.GetLength(); i++) Sfind.Name[i] = str[i];
Sfind.Name[str.GetLength()] = '\0';
if(str.IsEmpty()) ok1 = true;
str = m_Ftel;
str.TrimLeft(); str.TrimRight();
for(i = 0; i < str.GetLength(); i++) Sfind.Number[i] = str[i];
Sfind.Number[str.GetLength()] = '\0';
if(str.IsEmpty()) ok2 = true;
Sfind.group_index = m_Flist.GetCurSel();
if(Sfind.group_index == 0) ok3 = true;
if(ok1 && ok2 && ok3){
MessageBox("請填寫查找信息");
}
else{
que[0] = 0;
CString s1, s2;
CString check;
for(int i = 0; i <= m_tot; i++){
if(Sfind.group_index != 0 && Sfind.group_index != (People[i].group_index+1)) continue;
s1.Format("%s", Sfind.Name); s2.Format("%s", People[i].Name);
check = s1 + " " + s2;
if(!s1.IsEmpty() && s2.Find(s1) == -1) continue;
s1.Format("%s", Sfind.Number); s2.Format("%s", People[i].Number);
if(!s1.IsEmpty() && s2.Find(s1) == -1) continue;
que[++que[0]] = i;
}
check.Format("共查到%d條聯繫人", que[0]);
MessageBox(check);
}
// TODO: Add your control notification handler code here
}
void CZbookDlg::OnButtonPre()
{
if(m_nowpos == 1) {
MessageBox("toutou");
}else{
m_list.SetItemState(que[m_nowpos--], 0, LVIS_SELECTED|LVIS_FOCUSED);
m_list.SetItemState(que[m_nowpos], LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
}
// TODO: Add your control notification handler code here
}
void CZbookDlg::OnButtonNxt()
{
if(m_nowpos == que[0]){
MessageBox("weiwei");
}
else{
m_list.SetItemState(que[m_nowpos++], 0, LVIS_SELECTED|LVIS_FOCUSED);
m_list.SetItemState(que[m_nowpos], LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
}
// TODO: Add your control notification handler code here
}
跟計劃的差了一些, 計劃是周天晚上就搞定的, 果然還是有許多問題。 到目前, 基本功能都已經完成了, 但還是有許多細節沒有處理。
目前最大的一個問題就是 Clistctrl失焦問題,什麼事失焦, 就是當鼠標點擊clistctrl列表時, 被選中的信息有高亮, 當點到外邊(或者別的按鈕)的時候, 就沒有高亮了。 上網找了很多解決辦法, 都很難, 不是很容易實現。 又要拖到明天了。。
還有文件的讀寫問題。。 慘
又搜了幾個帖子, 發現一個可行的正解, 收一下 如何讓CListCtrl選中行恆保持其藍色高亮狀態?。 或者我再想想有沒有更好的查詢交互方法。
今天就只能完成這麼多了
週一早晨
決定改一下查找的方式, 變成根據關鍵字查找之後把所有符合條件的都顯示在列表框。
這要的話就要解決這幾個問題:
1. 添加聯繫人的時候, 如果當前列表框是全部列表框, 則直接添加, 否則就會清空當前的篩選然後直接列出全部聯繫人, 在添加最新的。 或者根本不考慮是不是全部列表,直接暴力全部刪除再全部添加。
2. 去掉上一個 下一個按鈕。
3. 優化修改和刪除按鈕可點擊情況。
今晚填補了之前挖的坑, 先說一下解決方案把, 修改了查詢的顯示結果, 直接讓結果顯示在列表欄裏, 這樣的話就方便的做到根據姓名+電話+分組查詢的同時修改+查詢。
方法是用之前的隊列始終維護列表裏有那些人(存實際數組中的下標)。
當添加聯繫人的時候, 直接刷新顯示全部聯繫人, 其他情況沒有影響。
查詢的時候, 隊列清空, 重新查詢, 滿足的放到隊列裏, 然後輸出到列表上。
刪除和修改的時候, 獲得的是列表中的下標, 通過隊列能夠查詢到在People數組中的實際下標, 進而實現修改和刪除。
大的bug也調完了, 小的bug發現了再調。
上一個效果圖:
最後, 要解決的問題就是數據的文件寫入保存問題。
我是用CStdioFile 形式實現讀寫的文件。
具體實現方法: 保存: 首先多加了一個保存按鈕:
void CZbookDlg::OnButtonSave()
{
CStdioFile file;
file.Open("test.txt",CFile::modeCreate|CFile::modeWrite);
CString str;
for(int i = 0; i <= m_tot; i++){
str.Format("%s\n", People[i].Name);
file.WriteString(str);
str.Format("%s\n", People[i].Number);
file.WriteString(str);
str.Format("%s\n", People[i].E_mail);
file.WriteString(str);
str.Format("%d\n", People[i].group_index);
file.WriteString(str);
str.Format("%s\n", People[i].Information);
file.WriteString(str);
}
MessageBox("保存成功");
// TODO: Add your control notification handler code here
}
然後在Myclass 寫了一個初始讀入的函數
void Myclass::Readbook()
{
CStdioFile file;
CString str;
file.Open("test.txt", CFile::modeRead);
int now = 0;
while (file.ReadString(str) != NULL)
{
int i;
if(now == 0) {
m_tot++;
for(i = 0; i < str.GetLength(); i++) People[m_tot].Name[i] = str[i];
People[m_tot].Name[str.GetLength()] = '\0';
}
else if(now == 1){
for(i = 0; i < str.GetLength(); i++) People[m_tot].Number[i] = str[i];
People[m_tot].Number[str.GetLength()] = '\0';
}
else if(now == 2){
for(i = 0; i < str.GetLength(); i++) People[m_tot].E_mail[i] = str[i];
People[m_tot].E_mail[str.GetLength()] = '\0';
}
else if(now == 3){
int x = People[m_tot].group_index = _ttoi(str);
if(x == 0) strcpy(People[m_tot].Group, "無");
else if(x == 1) strcpy(People[m_tot].Group, "家人");
else if(x == 2) strcpy(People[m_tot].Group, "同事");
else if(x == 3) strcpy(People[m_tot].Group, "朋友");
}
else if(now == 4){
for(i = 0; i < str.GetLength(); i++) People[m_tot].Information[i] = str[i];
People[m_tot].Information[str.GetLength()] = '\0';
}
now++; now %= 5;
}
}
在主窗口初始化的時候調用這個函數就行了。
感受, 用CString 和 char* 轉來轉去的感覺自己做麻煩了, 如果直接用CString儲存的話代碼肯定會短很多, 但是不知道會不會有錯。
其他地方基本滿意, 特別是查詢模塊換了思路之後, 可以支持修改和刪除, 更符合真正意義上的程序。
之後還會再修復bug, 可能還會做一些美化,(如果有時間的話), 畢竟期末了 其他科也需要複習。