通過小練習掌握MFC知識點之起步篇-父子視窗間傳值、ListCtrl隔行變色、雙緩衝技術解決控制項閃爍、自訂訊息等

來源:互聯網
上載者:User

2013.4.12 再次修改  

2013.4.11 修改  

註:修改內容見文章結尾處

本次練習會學到的知識點:

1、ListCtrl控制項:設定ListCtrl網格,內容項隔行變色,插入一行資料,刪除資料,選中整行,雙緩衝技術解決閃爍問題等。。

2、模態對話方塊及非模態對話方塊的使用

3、父子視窗間傳值

如果對話方塊是模態的,那麼彈出後該程式的其它視窗就呈停用狀態,原來的程式暫停執行,直到這個模態視窗關閉後才回到原來程式繼續。非模態的就是直接顯示出來,然後原來的程式繼續執行下面的語句,而且其它視窗也呈可用狀態。

題目:MFC資料結構的運用

要求:

1、  對話方塊中的表格,使用CListCtrl,採用REPORT風格、單選模式。表格由2列組成,第一列名稱“標題”,第二列名稱“內容”。

2、  點擊“添加”按鈕,彈出如所示的新對話方塊。輸入完畢後,點擊“確定”,添加到列表中。

注意:列表中的“標題”一列,要求不能重複。

3、  點擊“刪除”按鈕,可刪除列表中,當前選擇行。

注意:刪除後,當前行,位置下移一行。但如果刪除的是末尾行,保持當前行仍然是末尾行。

4、  點擊“查詢”按鈕。彈出如所示的非強制回應對話方塊,輸入“標題”後,點擊“尋找”,系統自動顯示CListCtrl列表中,與此“標題”對應的“內容”。

注意:所示對話方塊,要求採用非強制回應對話方塊,多次點擊查詢按鈕,只能彈出1個尋找對話方塊。

採用(映射)資料結構CMapStringToSting。

5、  點擊“發送”按鈕,彈出如所示的新對話方塊。將“習題2”對話方塊中的CListCtrl列表裡的內容,匯入新對話方塊列表中。並要求,新對話方塊風格和“習題2”對話方塊保持一致

第一版經檢查紕漏百出,各種問題迎面而來。如添加時,每次都new了一塊空間出來,而程式只在最後delete了一次,記憶體流失的情況可想而知。另外,第一版的單例模式設計得相當不得體,有分配但是沒有釋放。

//單例模式    static CFindDataDlg* GetInstance(){//問題:沒有在相應位置釋放,造成記憶體流失//if (NULL == m_pInstance)//{//m_pInstance = new CFindDataDlg;//}//return m_pInstance;static CFindDataDlg dlg; //如此一番更改後不用管理記憶體return &dlg;}

另外還要將類的建構函式,拷貝建構函式,解構函式以及賦值運算子多載都私為私人,避免被類外面的代碼調用到。

private:        CFindDataDlg(CWnd* pParent = NULL);CFindDataDlg(CFindDataDlg&);virtual ~CFindDataDlg();CFindDataDlg operator= (const CFindDataDlg&);

關於單例模式的設計請參考http://blog.csdn.net/boyhailong/article/details/6645681

關於自訂訊息傳遞

往父視窗發送自訂訊息

GetParent()->SendMessage(WM_USRMSG_ADD,WPARAM(&m_strTitle),LPARAM(&m_strContent));//整型的長度與指標的長度一致,傳遞指標沒問題

LRESULT CExercise3Dlg::OnAddData( WPARAM wParam, LPARAM lParam )//自訂訊息步驟3{//CString strSrc = m_pDlgAddData->GetTitle();//以前這種方式較為死板CString strTitle = *(CString*)wParam;//此種方式較為靈活//相當於CString pStrTitle = (CString*)wParam;CString strContent = *(CString*)lParam;}

自訂訊息處理的步驟:

1:明確哪個是發送方,哪個是接收方。本例中主視窗是接收方,而添加視窗則是發送方。

2:在發送方標頭檔中添加

#define WM_USRMSG_ADD (WM_USER + 100)//自訂訊息步驟1 

WM_USRMSG_ADD由使用者自己定義

3:在接收方標頭檔中聲明訊息響應函數

//訊息響應,添加資料 自訂訊息步驟2afx_msg LRESULT OnAddData( WPARAM wParam, LPARAM lParam );    DECLARE_MESSAGE_MAP()

4:訊息映射

BEGIN_MESSAGE_MAP(CExercise3Dlg, CDialog)//}}AFX_MSG_MAPON_MESSAGE(WM_USRMSG_ADD, OnAddData)ON_MESSAGE(WM_USRMSG_FIND,OnFindData)END_MESSAGE_MAP()

5:在接收方實現檔案(CPP)中定義自訂訊息響應函數

LRESULT CExercise3Dlg::OnAddData( WPARAM wParam, LPARAM lParam )//自訂訊息步驟3{......//實現功能}

6:在發送方實現檔案(CPP)中需要發送訊息的程式碼片段中發送訊息

//this->SendMessage(WM_USRMSG_ADD,0,0);//自訂訊息步驟4 //向父視窗發送訊息,而不是給自己,所以不應該用thisGetParent()->SendMessage(WM_USRMSG_ADD,WPARAM(&m_strTitle),LPARAM(&m_strContent));

怎麼樣?自訂訊息還是很簡單的吧。在這裡需要提醒一下SendMessage與PostMessage的區別:

PostMessage只負責將訊息放到訊息佇列中,不確定何時及是否處理SendMessage要等收到訊息處理的返回碼(DWord類型)後才繼續PostMessage執行後馬上返回SendMessage必須等到訊息被處理後才會返回
注意,不要通過PostMessage傳遞臨時變數指標,應該很可能訊息被處理時該變數已經銷毀,這時訪問就會出錯

使用者當前沒有選中ListCtrl控制項時,刪除按鈕應該是不可用狀態,當選中時呈可用狀態,並詢問是否刪除。如果沒有選中其中一行,刪除按鈕再次變為不可用。

添加訊息處理NM_CLICK

void CExercise3Dlg::OnNMClickList(NMHDR *pNMHDR, LRESULT *pResult){// TODO: 在此添加控制項通知處理常式代碼*pResult = 0;LPNMITEMACTIVATE pNMItem = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);if (-1 == pNMItem->iItem)//當前沒有選中行   iTem即當前選中行的行號{GetDlgItem(IDC_BTN_DEL)->EnableWindow(FALSE);}else{GetDlgItem(IDC_BTN_DEL)->EnableWindow(TRUE);}}

在修改版中存在兩個問題:

一是當先開啟"尋找"對話方塊時,主視窗ListCtrl的內容都已被複製一份到尋找類的成員變數中,此時ListCtrl傳過來的值已經確定,再開啟“添加”時,添加得到的新內容是無法傳入“尋找”類中的,所以也就無法正確尋找新添加的值。刪除操作也是這樣的的問題。

二是將可以用更簡單更容易理解的方式開啟尋找視窗,即將尋找類定義為主視窗的資料成員,結合Create()、IsWindowVisible()、DoModal()、SetFocus()這幾個函數可以保證每次只彈出一個執行個體。

在主視窗的建構函式中Create();

m_DlgFindData.Create(IDD_DIALOG_FIND, this);

接下來是在相應的函數中添加以下代碼

if (!m_DlgFindData.IsWindowVisible()) //如果視窗目前不是顯示狀態{int nCount = m_lstCtrl.GetItemCount();//CMapStringToString mapSTSData;//for (int i = 0; i < nCount; ++i)//mapSTSData[m_lstCtrl.GetItemText(i,0)] = m_lstCtrl.GetItemText(i, 1);//m_DlgFindData.SetMapData(mapSTSData);m_DlgFindData.SetMapData(&m_mapLstData);   m_DlgFindData.ShowWindow(TRUE);m_DlgFindData.SetFocus();}else{m_DlgFindData.SetFocus();//設定當前焦點}

問題一的解決辦法:

方法1、可以將添加視窗改成模態的方式(當前是非模態方式,即new->Create->ShowWindow),用DoModal方法保證運行添加操作時不可執行尋找操作。當新添加一條資料後,資料會在ListCtrl控制項中更新,再執行尋找操作時會先更新尋找類的成員變數,以更新資料再進行尋找。這樣可以保證程式無差錯。此種方法最容易想,同時也最方便。讀者可以自行修改代碼,這裡不作贅述。

方法2、還是以非模態方式調用,大致思路是:在主視窗(父視窗)類中定義一個資料成員,用於即時更新ListCtrl的內容,當執行添加或者刪除操作時,對應著更新這個資料成員。執行尋找操作時,將主視窗的這個資料成員的指標傳遞給尋找視窗(子視窗)對應的類中(在尋找類中定義一個對應類型的資料成員指標),那麼取資料時直接用的主視窗的即時資料。此種方法相對於以前那種尋找視窗複製一份主視窗ListCtrl內容的方式而言非常高效,而且簡單、安全、易理解,還節約了大量記憶體空間。在大量資料傳遞時表現得尤其明顯。所以這裡Ajioy大力推薦此種方法。

//查詢void CExercise3Dlg::OnBnClickedBtnQuery(){//需要用到單例模式?if(NULL == m_pDlgFindData){m_pDlgFindData = CFindDataDlg::GetInstance();CMapStringToString mapSTSData;int nCount = m_lstCtrl.GetItemCount();for (int i = 0; i < nCount; ++i){mapSTSData[m_lstCtrl.GetItemText(i,0)] = m_lstCtrl.GetItemText(i,1);}//m_pDlgFindData->SetMapData(mapSTSData);//低效,不推薦        m_pDlgFindData->SetMapData(&m_mapLstData);//十分高效,簡單安全易理解m_pDlgFindData->Create(IDD_DIALOG_FIND,this);}else{m_pDlgFindData->SetFocus();}m_pDlgFindData->ShowWindow(TRUE);}
void CFindDataDlg::SetMapData(const CMapStringToString* mapData){//INT_PTR nCount = mapData.GetSize();//const CMapStringToString::CPair* pCurVal;//pCurVal = mapData.PGetFirstAssoc();//while (NULL != pCurVal)//{//m_mapSTSData[pCurVal->key] = pCurVal->value; //pCurVal = mapData.PGetNextAssoc(pCurVal);//}m_pMapSTSData = mapData; //改用指標方式效率和效能都有提升,同時也減少了記憶體開銷}

記得在CFindDataDlg.h標頭檔中定義資料成員變數

const CMapStringToString* m_pMapSTSData;//父視窗CListCtrl中的內容

全方完

源碼地址:http://download.csdn.net/detail/ajioy/5241570(第一版,可下載對比修改版進行學習)

                    http://pan.baidu.com/share/link?shareid=471517&uk=805795666(修改版,代碼品質較高)

     http://pan.baidu.com/share/link?shareid=472397&uk=805795666(最終版,品質相當高呀)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.