VC開發多語言介面支援----INI實現(轉)

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

  初步設計用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();
  }
}
[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16396910/viewspace-1046829/,如需轉載,請註明出處,否則將追究法律責任。

相關文章