| 導購 | 订阅 | 在线投稿
分享
 
 
 

新設想——VC開發多語言界面支持的新招

來源:互聯網  2008-06-01 02:10:36  評論

最近在做一個小程序,要求實現對多語言界面顯示支持功能,並且,界面顯示內容用戶能夠自己設置。

初步設計用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設置方法,對給定的Frame或Dialog等Window容器組件內的所以組件進行遍曆,當增、減顯示組件不對語言包加載代碼産生影響,達到自適應界面組件語言包加載效果。

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

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

具體設計是:語言包配置文件就直接設置成組件ID與組件顯示信息的Hash表,Key = Value的形式,比如:BTnOK組件的ControlID爲「1003」,中文顯示Caption爲「登錄」,語言包配置內容就是「1003=登錄」。

語言包的加載過程爲2步實現:

首先,從語言包配置文件中,讀取所有配置的ID、Caption條目到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

...{

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

...{

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

...{

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

...{

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

...{

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();

}

}

  最近在做一個小程序,要求實現對多語言界面顯示支持功能,並且,界面顯示內容用戶能夠自己設置。   初步設計用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設置方法,對給定的Frame或Dialog等Window容器組件內的所以組件進行遍曆,當增、減顯示組件不對語言包加載代碼産生影響,達到自適應界面組件語言包加載效果。   這樣就産生一個新問題:語言包配置文件中的Caption值如何跟相關的組件正確地一一對應?   好友文國慶建議:用XML文件來定義這種對應關系。這個想法觸動了我:反正就是一個[Key,Value]的數據,就用已經實現的INI配置文件也可以啊。于是所有問題解決!   具體設計是:語言包配置文件就直接設置成組件ID與組件顯示信息的Hash表,Key = Value的形式,比如:BTnOK組件的ControlID爲「1003」,中文顯示Caption爲「登錄」,語言包配置內容就是「1003=登錄」。   語言包的加載過程爲2步實現:   首先,從語言包配置文件中,讀取所有配置的ID、Caption條目到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   ...{   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   ...{   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   ...{   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   ...{   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   ...{   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();   }   }
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有