【轉】[VC/MFC]MSFlexGrid 內嵌控件

[VC/MFC]MSFlexGrid 內嵌控件(附源代碼下載)

作者:茂葉 [轉貼] 瀏覽量: 4731 發表日期:2006-12-17 更新日期:2006-12-17

 

Key Words: MSFlexGrid 內嵌控件

 

http://www.maoyeah.com/display.asp?boardid=3&id=35


在VC中MSFlexGrid內嵌EDIT、COMBOBOX的實現方法 
    在CSDN網絡中經常會看到有人問起各種GRID控件內嵌EDIT、COMBOBOX的實現方法,本人在前階段的開發中也遇到這方面的困難,在網絡上找了又找,大多是針對ListView和DBGrid的,而對於MSFlexGrid的實現,則少之又少。在廣大網友的支持下,終於本人找到了實現MSFlexGrid內嵌EDIT、COMBOBOX的一種方法,我想本文對於採用MSFlexGrid進行應用開發的朋友一定有相當大的幫助。 

    總結一些網友以及本人在最初實現MSFlexGrid內嵌控件失敗的原因,大多是由兩方面造成的: 

1、座標系轉換問題,MSFlexGrid採用的座標系和一般的控件不同,所以在操作時,需要進行轉換。 
2、控件在創建上的問題,如果你把控件直接創建在主窗口中,那麼往往會存在,程序運行時,鼠標一點網格,控件就HIDE掉,所以在創建控件EDIT、COMBOBOX時,要以FlexGrid爲父窗口。 

    下面,我用一個示例程序來簡單的說明一下,同時我們的示例程序還實現了在FlexGrid中按TAB鍵跳至下一網格[下面提到的網格均指MSFlexGrid中的小單元格]的功能。想要源代碼的請登http://www.maoyeah.com/display.asp?boardid=3&id=35

首先,在對話框的初始化中調用我們的初始化函數: 

void CProg5Dlg::InitControls() 

//創建各個內嵌控件 
m_edit.Create(WS_CHILD,CRect(0,0,0,0),&m_FlexGrid,IDC_EDIT); 
m_cmb.Create(WS_CHILD|CBS_DROPDOWNLIST,CRect(0,0,0,0),&m_FlexGrid,IDC_CMB); 
//設置爲和主窗口相同字體 
m_edit.SetFont(GetFont()); 
m_cmb.SetFont(GetFont()); 
//用數據填充Grid 和 ComboBox 
long lRow ; 
long lRowCount = m_FlexGrid.GetRows(); 
long lCol ; 
long lColCount = m_FlexGrid.GetCols(); 
for (lRow = 1; lRow < lRowCount; lRow++) 

        m_FlexGrid.SetRow(lRow); 
        for(lCol = 1; lCol < lColCount; lCol++) 
        { 
               m_FlexGrid.SetCol(lCol); 
               CString strText; 
               strText.Format("%ld-%ld",lRow,lCol); 
               //用數據填充Grid 
               m_FlexGrid.SetText(strText); 
               //用數據填充ComboBox 
               m_cmb.AddString(strText); 
        } 

}  

其中m_edit、m_cmb是我們聲明的類數據成員: 
private: 
CEdit m_edit; 
CComboBox m_cmb; 

它們的創建一定要用.Create的方法並以MSFlexGrid爲父窗口,要不然,程序運行時,你一點MsflexGrid,你的Edit或ComboBox就不見了 [這是因爲,MSFlexGrid和你的Edit或ComboBox同以Dialog爲父窗口,你點了MsflexGrid,在Z座標上,它就蓋住了你的內嵌控件] ,因爲在創建之後,它們採用的字體可能和你的主窗口風格不一致,所以還要設置一下字體。 

接下來就是程序中最重要的一個函數了: 

void CProg5Dlg::GridEdit(WORD nKeyAsciiCode, CWnd *p_wnd) 

if(p_wnd == NULL) 
{//得到當前編輯的網格的內嵌控件是m_edit or m_cmb 
        p_wnd = GetThisCellMaskControl(); 


ASSERT(p_wnd != NULL); 

//支持座標變換 
CDC* pDC = m_FlexGrid.GetDC(); 
int nLogX = pDC->GetDeviceCaps(LOGPIXELSX); 
int nLogY = pDC->GetDeviceCaps(LOGPIXELSY); 
ReleaseDC(pDC); 
CString sz; 
//當有文字輸入時,如果當前控件是Edit,那麼光標到末尾 
if (nKeyAsciiCode >= 0 && nKeyAsciiCode < ’ ’) 

        if(p_wnd->IsKindOf(RUNTIME_CLASS(CEdit))) 
        { 
               ((CEdit *)p_wnd)->SetSel(-1, -1); 
        } 

else 

        CString Input = "  "; 
        p_wnd->GetWindowText(sz);        

        if (nKeyAsciiCode > 0x100) 
        {//用來支持漢字輸入 
               Input.SetAt(0, nKeyAsciiCode >> 8); 
               Input.SetAt(1, nKeyAsciiCode & 0xff); 
        } 
        else 
        {//非漢字 
               Input = (char)nKeyAsciiCode; 
        } 
        sz += Input; 
        p_wnd->SetWindowText(sz);  
}  

if(p_wnd->IsKindOf(RUNTIME_CLASS(CComboBox))) 

        p_wnd->MoveWindow( 
        (m_FlexGrid.GetCellLeft() * nLogX)/1440 - 3,  
        (m_FlexGrid.GetCellTop() * nLogY)/1440  - 3, 
        (m_FlexGrid.GetCellWidth()* nLogX)/1440 ,  
        (m_FlexGrid.GetCellHeight()* nLogY)/1440 + 100,FALSE); 


else if(p_wnd->IsKindOf(RUNTIME_CLASS(CEdit))) 

p_wnd->MoveWindow( 
        (m_FlexGrid.GetCellLeft() * nLogX)/1440 - 3,  
        (m_FlexGrid.GetCellTop() * nLogY)/1440  - 3, 
        (m_FlexGrid.GetCellWidth()* nLogX)/1440,  
        (m_FlexGrid.GetCellHeight()* nLogY)/1440,FALSE); 

else 

        ASSERT(0); 


//顯示我們的控件 
p_wnd->ShowWindow(SW_SHOW); 
p_wnd->SetFocus(); 
p_wnd->GetWindowText(sz);  

if(p_wnd->IsKindOf(RUNTIME_CLASS(CEdit))) 

       ((CEdit *)p_wnd)->SetSel(sz.GetLength(), sz.GetLength(), FALSE); 
}  

m_FlexGrid.RedrawWindow(); 
}  

[說明:這個函數部分代碼並非原創] 

這個函數的作用,主要是支持MSFlexGrid的編輯,並把你的內嵌控件顯示出來,當然,如果它是一個EDIT,那麼我們有責任把EDIT內的光標置於EDIT中字串的最後。這個函數有兩個參數: 

WORD nKeyAsciiCode:如果激活編輯FlexGrid的事件是一次按鍵,那麼這個參數當然就和按鍵的信息有關了,另外在函數中,通過它可以實現支持中文,比如:您把焦點放到一個內嵌爲EDIT的網格中[只是讓FlexGrid的網格得到焦點,而不讓內嵌的EDIT顯示出來],直接輸入中文,然後就會發現,網格自動進入編輯狀態,並且你輸入的中文漢字位於字串的最後: 

第二個參數: 
 CWnd *p_wnd可以指定你想使用的內嵌控件,傳入時可以使用&m_edit或&m_cmb。 

當然,你可以不指定它而用我們當初設置好的規則[這規則是指MSFlexGrid哪列固定採用哪個內嵌控件],這是用什麼實現的呢? 

看到函數GridEdit中的 

if(p_wnd == NULL) 

        p_wnd = GetThisCellMaskControl(); 


了吧? 

CWnd * CProg5Dlg::GetThisCellMaskControl() 

switch(m_FlexGrid.GetCol()) 

//第一列,第三列用ComboBox做爲內嵌控件 
case 1: 
case 3: 
        return &m_cmb; 
        break; 
//其它的用Edit 
default: 
        return &m_edit; 



  

我們可通過這個函數來設定一些基本規則。 
那麼GridEdit函數是由誰來調用的呢?答案當然是由想實現編輯網格的事件觸發的,在這裏我設定爲鼠標雙擊和網格有焦點時的按鍵事件:

//鼠標雙擊激發 
void CProg5Dlg::OnDblClickMsflexgrid()  

//第一行和第一列是固定的,我不想編輯它們 
if(m_FlexGrid.GetCol() == 0 || m_FlexGrid.GetRow() == 0) 
        return; 
GridEdit(0,NULL);  


  

//按鍵事件激發 
void CProg5Dlg::OnKeyPressMsflexgrid(short FAR* KeyAscii)  

// TODO: Add your control notification handler code here 
if(m_FlexGrid.GetCol() == 0 || m_FlexGrid.GetRow() == 0) 
        return; 
GridEdit(*KeyAscii,NULL); 


  

引發這個函數之前,我們最好把ComboBox的當前選擇內容和Edit的內容設爲要編輯的那個格子的內容: 
void CProg5Dlg::OnEnterCellMsflexgrid()  

// TODO: Add your control notification handler code here 
int nthisRow = m_FlexGrid.GetRow(); 
if(nthisRow == 0) 

        return; 


CString sz; 
sz = m_FlexGrid.GetText(); 
CWnd *pWnd = GetThisCellMaskControl(); 

if(pWnd->IsKindOf(RUNTIME_CLASS(CComboBox))) 

        ((CComboBox *)pWnd)->SelectString(-1,sz); 

else if(pWnd->IsKindOf(RUNTIME_CLASS(CEdit))) 

        pWnd->SetWindowText(sz); 

else 

        ASSERT(0); 



  

你覺得這樣就行了嗎?當然不行!我們在把焦點移到其它網格時[只是把焦點移走],我們有必要把那個已經顯示出來的內嵌控件HIDE掉,並把它的內容傳給網格,這也是我們編輯的目的。 

void CProg5Dlg::OnLeaveCellMsflexgrid()  

// TODO: Add your control notification handler code here 
int nthisRow = m_FlexGrid.GetRow(); 
if(nthisRow == 0) 

        return; 


CString sz; 
CWnd * p_ThisWnd = GetThisCellMaskControl(); 
ASSERT(p_ThisWnd != NULL); 
if (p_ThisWnd->IsWindowVisible()) 

        p_ThisWnd->GetWindowText(sz); 
        m_FlexGrid.SetText(sz);   
        p_ThisWnd->ShowWindow(SW_HIDE); 



基本上差不多了。 

  

下面簡單介紹一下用Tab實現在MSFlexGrid的網格中跳轉的問題。 

我一看到這種應用,馬上想到採用PreTranslateMessage函數,這個函數可是真好用,一般實現什麼窗口內焦點的跳轉我都用它。 
在實現它之前,我們先定義一個跳到一下格子的函數: 
void CProg5Dlg::GoToNextCell() 

if(m_FlexGrid.GetCol() == m_FlexGrid.GetCols() - 1) 

        if(m_FlexGrid.GetRow() != m_FlexGrid.GetRows() - 1) 
        { 
               m_FlexGrid.SetRow(m_FlexGrid.GetRow() + 1); 
               m_FlexGrid.SetCol(1); 
        } 
        else 
        { 
               return; 
        } 

else 

        m_FlexGrid.SetCol(m_FlexGrid.GetCol() + 1); 



  

在我們的PreTranslateMessage會調用它實現跳到下一網格中: 
BOOL CProg5Dlg::PreTranslateMessage(MSG* pMsg)  

// TODO: Add your specialized code here and/or call the base class 
CWnd *pWnd = CWnd::FromHandle(pMsg->hwnd); 
CWnd *pCon = GetThisCellMaskControl(); 

if(pMsg->message!=WM_KEYDOWN) 
               return CDialog::PreTranslateMessage(pMsg); 
switch(pMsg->wParam) 

case VK_TAB: 
        if(pCon->GetSafeHwnd() == pMsg->hwnd) 
        {//如果按TAB時,處於EDIT狀態,也會跳到下一格子 
               GoToNextCell(); 
               return TRUE; 
        } 
        switch(pWnd->GetDlgCtrlID()) 
        { 
case IDC_MSFLEXGRID: 
               GoToNextCell(); 
               return TRUE; 

break; 
}  
return CDialog::PreTranslateMessage(pMsg); 
}  

好了,整個應用就講完了,我想對於採用MSFlexGrid實現應用的朋友們,這個小東東一定能起到拋磚引玉的作用。 

發佈了34 篇原創文章 · 獲贊 3 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章