VC開發多語言介面支援的簡單方法

gudesheng發表於2008-01-03

VC開發多語言介面支援的簡單方法

作者:成曉旭

(需要完整原始碼請留言)

最近在做一個小程式,要求實現對多語言介面顯示支援功能,並且,介面顯示內容使用者能夠自己設定。

初步設計用INI檔案來配置顯示內容,換一種語言的配置檔案,就能夠更換整個系統的顯示語言。考慮到系統規模很小,週期又短,不想用太複雜的方案來解決這個問題,當參考了很多網上類似的設計和程式碼,發現都不是很滿意。

主要問題在於:絕大多數基於INI檔案配置這種簡單應有實現的程式碼,都是針對元件ID固定載入,寫死了元件的ID號,比如:

strCaption = fileManager.GetString(section,"IDC_Stc_ListStudent","");

SetDlgItemText(IDC_Stc_ListStudent,strCaption);

strCaption = fileManager.GetString(section,"IDC_Stc_AllContent","");

SetDlgItemText(IDC_Stc_AllContent,strCaption);

         這樣:介面元件越多,載入程式碼越長;每新增一個顯示視窗,又必須複製、貼上類似的程式碼,根據元件ID常量值來修改相關的載入項。很是不爽!

         初步設想是:設計統一、通用的視窗元件Caption設定方法,對給定的FrameDialogWindow容器元件內的所以元件進行遍歷,當增、減顯示元件不對語言包載入程式碼產生影響,達到自適應介面元件語言包載入效果。

         這樣就產生一個新問題:語言包配置檔案中的Caption值如何跟相關的元件正確地一一對應?

好友文國慶建議:用XML檔案來定義這種對應關係。這個想法觸動了我:反正就是一個[Key,Value]的資料,就用已經實現的INI配置檔案也可以啊。於是所有問題解決!

具體設計是:語言包配置檔案就直接設定成元件ID與元件顯示資訊的Hash表,Key = Value的形式,比如:BtnOK元件的ControlID為“1003,中文顯示Caption為“登入”,語言包配置內容就是“1003=登入”。

語言包的載入過程為2步實現:

首先,從語言包配置檔案中,讀取所有配置的IDCaption條目到Vector或者Array中。

其次,在遍歷指定視窗中所有元件時,每發現一個元件,就用其ID在已經載入的語言包陣列中查詢,找到就用配置的值修改元件Caption屬性;找不到,就認為是不需要動態配置,不做處理。

配置檔案例項:

配置項解釋:Section[Login Dialog]介面視窗;等號左邊:視窗中需要設定其Caption屬性的元件ID;等號左邊:視窗中需要設定其Caption屬性的元件Caption值;

[Login Dialog]

1001 = 使用者帳號

1002 = 使用者密碼

1017 =  

1018 = 退 

語言包配置資訊載入程式碼:

 

 
BOOL CLanguageManager::loadFromFile()
{
    BOOL bRead
=FALSE;
    
int i;
    ItemContext temp;
    CStringArray itemBuf,valueBuf;
    bRead 
= fileManager.GetSectionValues("Main Window",itemBuf,valueBuf);
    
if(bRead) 
    
{
        
for(i=0;i<itemBuf.GetSize();i++)
        
{
            temp.uCtrlID 
= atoi(itemBuf.GetAt(i));
            temp.strContext 
= valueBuf.GetAt(i);
            m_vtContexts.push_back(temp);
        }

    }

    itemBuf.RemoveAll();
    valueBuf.RemoveAll();
    
    bRead 
= fileManager.GetSectionValues("Login Dialog",itemBuf,valueBuf);
    
if(bRead) 
    
{
        
for(i=0;i<itemBuf.GetSize();i++)
        
{
            temp.uCtrlID 
= atoi(itemBuf.GetAt(i));
            temp.strContext 
= valueBuf.GetAt(i);
            m_vtContexts.push_back(temp);
        }

    }

    
return bRead;
}

 

讀取語言包配置資訊:

BOOL CIniFile::GetSectionValues(CString Section, CStringArray &strItemBuf, CStringArray &strValueBuf)
{
    BOOL bRead 
= FALSE;
    ReadIniFile();
//開啟檔案

    
if(bFileExist == FALSE || FileContainer.GetSize() < 0)
        
return bRead;//檔案開啟出錯或檔案為空,返回預設值

    
int i = 0;
    
int iFileLines = FileContainer.GetSize();
    CString strline,str;

    
while(i<iFileLines)
    
{
        strline 
= FileContainer.GetAt(i++);

        strline.TrimLeft();
        
if(strline.GetLength()<=0)
            
continue;    //跳過空行
        if(strline.Left(2)=="//"
            
continue;    //跳過註釋行
        if(strline.GetAt(0)=='[')//查詢Section,第一個必須為[
        {
            str
=strline.Left(strline.Find("]"));//去掉]右邊
            str=str.Right(str.GetLength()-str.Find("[")-1);//去掉[左邊

            str.TrimLeft();
            str.TrimRight();

            
if(Section == str)//找到Section
            {
                
while(i<iFileLines)
                
{
                    strline 
= FileContainer.GetAt(i++);
                    strline.TrimLeft();
                    
if(strline.GetLength()<=0)
                        
continue;    //跳過空行
                    if(strline.GetAt(0)=='[')
                        
return bRead;//如果到達下一個[],即找不到,返回預設值
                    if(strline.Left(2)=="//"
                        
continue;    //跳過註釋行

                    str 
= strline.Left(strline.Find("="));//去掉=右邊
                    str.TrimLeft();
                    str.TrimRight();
                    
//儲存等號左邊項
                    strItemBuf.Add(str);

                    str
=strline.Right(strline.GetLength()-strline.Find("=")-1);//去掉=左邊
                    str.TrimLeft();
                    str.TrimRight();
                    
//儲存等號右邊項
                    strValueBuf.Add(str);
                    bRead 
= TRUE;
                }

                
//當前Section遍歷結束
            }

            
//沒有找到Section
        }

        
//當前行遍歷結束
    }

    
return bRead;
}

 

修改指定元件Caption屬性程式碼:

BOOL CLanguageManager::setControlCaption(CWnd * pCtrl, UINT ctrlID)
{
    BOOL isOK
=FALSE;
    
for(int i=0;i<m_vtContexts.size();i++)
    
{
        isOK 
= (m_vtContexts[i].uCtrlID==ctrlID);
        
if(isOK)
        
{
            pCtrl
->SetWindowText(m_vtContexts[i].strContext);
            
break;
        }

    }

    
return isOK;
}

 

遍歷設定指定視窗所有元件Caption屬性程式碼:

void CLanguageManager::setCaptionForWindow(CWnd * pWnd)
{
    
//列舉對話方塊中所有元件
    
    CWnd 
*pCtrl = pWnd->GetWindow(GW_CHILD);
    
while(pCtrl!=NULL)
    
{
        UINT ctrlID 
= pCtrl->GetDlgCtrlID();
        setControlCaption(pCtrl,ctrlID);
        pCtrl 
= pCtrl->GetNextWindow();
    }

}


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1764291


相關文章