C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Интернационализация приложения
Chernov
Отправлено: 18.08.2006, 15:37


Ученик-кочегар

Группа: Участник
Сообщений: 13



Ничего подобного не нашел, и написал сам. Вдруг кому надо.
В эту функцию передается указатель на форму, например this из CreateForm
CODE

void TranslateF(TForm * Form)
{
 if(Form)
 {
   Form->Position=poScreenCenter;//Позиционирование окна на центр экрана
   AnsiString cap=Form->Caption;
   int cou=Form->ComponentCount;
   for(int i=0;i<cou;i++)   //По всем компонентам на форме
   {

     if(Form->Components[i]->ClassNameIs("TLabel"))
     ((TLabel *)(Form->Components[i]))->Caption=Trans(cap,((TLabel *)(Form->Components[i]))->Caption);

     if(Form->Components[i]->ClassNameIs("TButton"))
     ((TButton *)(Form->Components[i]))->Caption=Trans(cap,((TButton *)(Form->Components[i]))->Caption);
   }
 }
}


Эта функция возвращает перевод слова в зависимости от указанного файла словаря. Здесь берется из реестра. Словарь это обычный ini файл.
конструкция такая
[Название формы]
Название кнопки=перевод
Если названия формы не существует берет из словаря
[General]
CODE

AnsiString Trans(AnsiString cap,AnsiString word)
{
TRegistry * fReg = new TRegistry(KEY_READ);
fReg->OpenKey("\\Software\\vasale", true);
AnsiString fn=fReg->ReadString("TranslateFile");   //INI-файл в котором храниться перевод
AnsiString res=word;
if (word.Length()>0)
{
 TIniFile * IniFile=new TIniFile(fn);
 res=IniFile->ReadString("General",word,res);   //Сперва просматривает раздел General
 if (cap.Length()>0)
 res=IniFile->ReadString(cap,word,res); //Перевод по разделу, зависимому от заголовка формы
 delete IniFile;
}
return res;
}


припер ini-файла:
CODE

[General]
New=Nuevo
Groups=Grupos
Select direction=Seleccione Destino
Touroperators=Touroperadores
Hotels=Hoteles
Places in Hotels=Cupo en Hoteles
Rates=Cambio
Trips=Vuelos
Transfers=Transfers
Сalculate package=Calculo del paquete
Users=Usuarios
Print Policy=Imprimir Poliza
OK=OK
Password=Contraseca

Это перевод на испанский. Не знаю на сколько точный.
AVC
Отправлено: 18.08.2006, 16:19


Ветеран

Группа: Модератор
Сообщений: 1583



Пара замечаний.
1. Если вы думаете, что обходите все компоненты формы, то вы заблуждаетесь (пример TPanel).
2. Проверяя на ClassName вы находите объекты данного класса, но не их наследников (это самое существенное для данного кода отличие от dynamic cast)

Мой пример: так проставляются стили всем нужным компонентам формы
CODE

extern bool __fastcall SetStyleForm (TForm* );
extern bool __fastcall SetStyleDBGrid (TDBGrid* );
extern bool __fastcall SetStyleDrawGrid (TDrawGrid* );
extern bool __fastcall SetStyleDBEdit (TDBEdit* );
extern bool __fastcall SetStyleDBMemo (TDBMemo* );
extern bool __fastcall SetStyleEdit (TEdit* );
extern bool __fastcall SetStyleMemo (TMemo* );
extern bool __fastcall SetStyleMemo (TRichEdit* );
extern bool __fastcall SetStyleMaskEdit (TMaskEdit* );
extern bool __fastcall SetStyleDBText (TDBText* );
extern bool __fastcall SetStylePanelBmp (TPanelBmp* );
extern bool __fastcall SetStylePanel (TPanel* );
extern bool __fastcall SetStyleLabelS (TLabelS* );
extern bool __fastcall SetStyleLabel (TLabel* );
extern bool __fastcall SetStyleButton (TButton* );
extern bool __fastcall SetStyleBitBtn (TBitBtn* );
extern bool __fastcall SetStyleStatusBar (TStatusBar* );
extern bool __fastcall SetStyleTileBmp (TTileBmp* );

//---------------------------------------------------------------------------
// Обход всех подчиненных объектов и расстановка стилей
//---------------------------------------------------------------------------

PACKAGE void __fastcall SetStyle (TObject *obj)
{
TControl *control = dynamic_cast<TControl*>(obj);
if (!control) return;

if (SetStyleLabelS (dynamic_cast<TLabelS*> (control)) );
else if (SetStyleLabel (dynamic_cast<TLabel*> (control)) );

else if (SetStyleMaskEdit (dynamic_cast<TMaskEdit*> (control)) );
else if (SetStyleDBEdit (dynamic_cast<TDBEdit*> (control)) );
else if (SetStyleDBMemo (dynamic_cast<TDBMemo*> (control)) );
else if (SetStyleDBText (dynamic_cast<TDBText*> (control)) );
else if (SetStyleMemo (dynamic_cast<TMemo*> (control)) );
else if (SetStyleMemo (dynamic_cast<TRichEdit*> (control)) );
else if (SetStyleEdit (dynamic_cast<TEdit*> (control)) );

else if (SetStyleDBGrid (dynamic_cast<TDBGrid*> (control)) );
else if (SetStyleDrawGrid (dynamic_cast<TDrawGrid*> (control)) );

else if (SetStyleBitBtn (dynamic_cast<TBitBtn*> (control)) );
else if (SetStyleButton (dynamic_cast<TButton*> (control)) );

else if (SetStyleStatusBar (dynamic_cast<TStatusBar*>(control)) );

else if (SetStylePanelBmp (dynamic_cast<TPanelBmp*> (control)) );
else if (SetStylePanel (dynamic_cast<TPanel*> (control)) );

else if (SetStyleTileBmp (dynamic_cast<TTileBmp*> (control)) );

else if (SetStyleForm (dynamic_cast<TForm*> (control)) );
else ;

TWinControl *wcontrol = dynamic_cast<TWinControl*>(control);
if (!wcontrol) return;

for (int i = 0; i < wcontrol->ControlCount; i++)
SetStyle (wcontrol->Controls[i]);

}

//---------------------------------------------------------------------------

bool __fastcall SetStyle__???__ (T??? *obj)
{
if (!obj) return false;
...
return true;

//---------------------------------------------------------------------------

Возможный вызов SetStyle(Form1);

Извините за ложку дёгтя. smile.gif

Отредактировано AVC — 18/08/2006, 15:22
Shagg
Отправлено: 19.08.2006, 07:22


Дежурный стрелочник

Группа: Участник
Сообщений: 69



Рекурсивная функция, расставляющая кэпшны для всех контролов:
CODE
void __fastcall SetChildCaption(TWinControl *Parent)
{
 TControl *Child;
 int i;
 for (i=0; i<Parent->ControlCount; i++)
 {
   Child = Parent->Controls[i];
   if (Child->ClassNameIs("TPanel"))
   {
     dynamic_cast<TPanel*>(Child)->Caption = IntToStr(i*i);
     SetChildCaption(dynamic_cast<TWinControl*>(Child));
   }
   else if (Child->ClassNameIs("TButton"))
     dynamic_cast<TButton*>(Child)->Caption = IntToStr(i*i);
   else if (Child->ClassNameIs("TEdit"))
     dynamic_cast<TEdit*>(Child)->Text = IntToStr(i*i);
   else if (Child->ClassNameIs("TLabel"))
     dynamic_cast<TLabel*>(Child)->Caption = IntToStr(i*i);
 }
}
Chernov
Отправлено: 21.08.2006, 10:48


Ученик-кочегар

Группа: Участник
Сообщений: 13



Спасибо.
Я так и не понял, что такое dynamic cast, но переписал все следующим образом.
CODE

void TranslateF(TForm * Form)
{
 if(Form)
 {
   Form->Position=poScreenCenter;//Позиционирование окна на центр экрана
   AnsiString cap=Form->Caption;
   int cou=Form->ComponentCount;
   for(int i=0;i<cou;i++)   //По всем компонентам на форме
   {
     TranslateComponent(cap,Form->Components[i]);
   }
 }
}


void TranslateControl(AnsiString cap, TWinControl * Control)
{
 if(Control)
 {
   int cou=Control->ControlCount;
   for(int i=0;i<cou;i++)   //По всем компонентам на форме
   {
     if(Control->ClassNameIs("TPageControl"))TranslateComponent(cap,((TPageControl*)Control)->Controls[i]);
   }
 }
}

void TranslateComponent(AnsiString cap, TComponent * Component)
{
     if(Component->ClassNameIs("TLabel"))
       ((TLabel *)(Component))->Caption=Trans(cap,((TLabel *)(Component))->Caption);
     if(Component->ClassNameIs("TButton"))
       ((TButton *)(Component))->Caption=Trans(cap,((TButton *)(Component))->Caption);

     if(Component->ClassNameIs("TTabSheet"))
       ((TTabSheet *)(Component))->Caption=Trans(cap,((TTabSheet *)(Component))->Caption);
     if(((TWinControl *)Component)->ControlCount)
       TranslateControl(cap,(TWinControl *)(Component));
}

И по аналогии с TPageControl c TPanel можно сделать и прочее прочее прочее
AVC
Отправлено: 21.08.2006, 11:26


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

Я так и не понял, что такое dynamic cast, но переписал все следующим образом.

Грубо говоря это попытка проверки "а приводим ли данный указатель к данному типу?" во время выполнения приложения. В данном случае основное отличие от ClassNameIs заключается в том, что ClassNameIs проверяет только на соответствии самому последнему из потомков. На практике это означает следующее:
Допустим я создал свой компонент на базе TLabel и назвал его TLabelS
Так вот для ClassNameIs
CODE

"TLabelS" -> true
"TLabel"  -> false
...
"TComponent" -> false
"TObject" -> false


а для dynamic_cast (если считать NULL как false а не NULL как true)
CODE

<TLabelS*> -> true
<TLabel*>  -> true
...
<TComponent*> -> true
<TObject*> -> true

А это означает, что если для чего то мне нужно свойство наследуемое от TLabel, то выгоднее писать dynamic_cast и не забивать себе голову, что я могу создать для разных слусаев разных потомков от TLabel, потомков от потомков и т.д. В случае d_c код переделывать не придется, а в случае использования ClassNameIs придется при определении каждого нового потомка.

QUOTE

И по аналогии с TPageControl c TPanel можно сделать и прочее прочее прочее

Зачем когда написав так можно вообще навсегда забыть о том что есть всякие Panel и прочее, прочее, прочее

TWinControl *wcontrol = dynamic_cast(control);
if (!wcontrol) return;

for (int i = 0; i < wcontrol->ControlCount; i++)
Функция_обрабатывающая_текущий_контрол (wcontrol->Controls[i]);

Вернуться в Вопросы программирования в C++Builder