Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как получить ВСЕ Caption ы контролов на форме? [D6, WinXP]


BlackTiger ©   (2002-12-10 20:41:00) 

Как получить ВСЕ Caption"ы контролов на форме?

Мне необходимо сохранить их в файле в виде
<имя контрола>=<его caption>

А потом загрузить все обратно.

Типа многоязычность получается.


Бурундук   (2002-12-11 20:29:00) [1]

Ф-я доступа к WideString св-вам для D5:

type
PVMTAsArray = ^VMTAsArray;
VMTAsArray = array[0..$FFFF]of Pointer;

function GetWStrProp(Instance: TObject; const PropName: string): WideString;
var PGetCode: Pointer;
Getter: TWStrGet;
Field: Pointer;
HiByte: Byte;
begin
PGetCode := GetPropInfo(Instance, "W")^.GetProc;
HiByte := Cardinal(PGetCode) shr 24;

TMethod(Getter).Data := Instance;
if HiByte = $FF then
begin
Cardinal(Field) := Cardinal(PGetCode)and $FFFFFF + Cardinal(Instance);
Result := WideString(Field^);
end else
if HiByte = $FE then
begin
TMethod(Getter).Code :=
PVMTAsArray(Instance.ClassType)[(Cardinal(PGetCode) and $FFFFFF) div 4];
// не индекс, а смещение - я ошибся
Result := Getter();
end
else
begin
TMethod(Getter).Code := PGetCode;
Result := Getter();
end;
end;


Бурундук   (2002-12-11 19:56:00) [2]

Только наоборот: $FE - вирт. ф-я, $FF - поле.
И это справедливо для D5, для D6 проверь сам.
(И посмотри в typinfo - может, в D6 уже есть более
удобный доступ к WideString св-вам).

И если у тебя только один компонент с таким Caption"ом
и больше не предвидится -
то, может, проще явно привести и не извращаться.


Бурундук   (2002-12-11 19:38:00) [3]

Привожу реализацию GetStrProp

function GetStrProp(Instance: TObject; PropInfo: PPropInfo): string;
begin
case PropInfo^.PropType^.Kind of
tkString: GetShortStrPropAsLongStr(Instance, PropInfo, Result);
tkLString: GetLongStrProp(Instance, PropInfo, Result);
tkWString: GetWideStrPropAsLongStr(Instance, PropInfo, Result);
// Автоматическое преобразование из WideString в AnsiString
else
Result := "";
end;
end;

Если же тебе надо получить именно WideString, то стандартных
доступов к WideString св-вам в RTTI я не вижу,
по крайней мере в D5.

Я полагаю, получить WideString через RTTI можно только
через функцию-Getter,
причём надо учитывать след. частные случаи:
1) старший байт адреса ф-и = $FE (если память мне не изменяет)- это не ф-я,
а смещение самого поля относительно начала объекта (-$FE, соотв)
2) -"- $FF: индекс виртуальной ф-и в VMT (тоже - $FF)
3) просто статический метод.


BlackTiger   (2002-12-11 19:26:00) [4]

:-)))
Совсем торможу уже... Пора отдыхать, отдыхать, отдыхать...
Я просто пытался найти TMenuItem в Controls[], а не в Components[].
И используя ComponentCount рыться в Controls[].

2Юрий Зотов:
GetStrProp результат какого типа возвращает? String (PChar, ShortString)?
Если да, то он мне не поможет, тк TNT-компоненты имеют Caption типа WideString и все данные потеряются, а в этом-то и вся фишка.

З.Ы.: Мое личное АААААААААААфигенноеспасибо разработчикам TNT-компонентов!!!


Юрий Зотов   (2002-12-11 19:10:00) [5]

> наличие Caption у контрола совсем не обязательно

Неправда. Все контролы имеют свойство Caption, только не у всех оно опубликовано.


> Ну и как получить/установить надписи на элементах меню по
> имени компонента?

uses
TypInfo;
...
S := GetStrProp(Components[i], "Caption");
...
SetStrProp(Components[i], "Caption", "Закрыть");


Бурундук   (2002-12-11 19:03:00) [6]

Так ведь TMenuItem - потомок TComponent, а не TControl,
и естественно, что его в Controls[] нет.
Зато он есть в Components[].

>Self.ComponentCount указывает на количество компонент большее, >чем можно адресовать в Self.Components[].

А вот это я не врубился.

Если тебе нужны TMenuItemы - то надо организовать
проход по всем компонентам (а не контролам):

for i := 0 to ComponentCount - 1 do
if GetPropInfo(Components[i], "Caption") <> nil then
ЧегоТоТам.Add(GetPropValue(Components[i], "Caption"));

PS Зачем ты везде Self таскаешь?
Это имеет смысл, только если у тебя код внутри with находится
(и не просто with, а with чего-то с такими же свойствами)


BlackTiger   (2002-12-11 18:51:00) [7]

То, что загнул - полностью огласен :-)

НО (!!!) прикол в том, что не могу достучаться до Caption у TMenuItem (TTntMenuItem). В списке Self.Controls[] они отсутствуют, при этом Self.ComponentCount указывает на количество компонент большее, чем можно адресовать в Self.Components[].

Ну и как получить/установить надписи на элементах меню по имени компонента?


Бурундук   (2002-12-11 18:24:00) [8]

>Self.FindComponent(Self.Controls[i].Name)
Ну ты и загнул... Я б так не смог.

По сути:
Используй RTTI

var CompCaption: string;

if Has...
CompCaption := GetPropValue(Controls[i], "Caption") // - получение заголовка в виде AnsiString не зависимо от типа.

Это сработает, даже если у какой-нибудь кнопки св-во Caption имеет тип Integer :)))


BlackTiger   (2002-12-11 17:11:00) [9]

Спасибо, конечно, но наличие Caption у контрола совсем не обязательно, а использовать try - довольно убогое решение.
Я нашел код, который проверяет наличие какого либо свойства (проверял только для Caption) в библиотеке IniLang.
Если кому надо, то вот он

function HasProperty(comp:TComponent;prop:String):boolean;
begin
result:=(getPropInfo(comp.classInfo,prop)<>nil) and comp.name<>"");
end;

Используется так

if HasProperty(Button1, "Caption") then begin
// ...
end;

Правда для TNT-компонентов приходится извращаться и определять класс компонента более точно.

var
ws: WideString;
wsl: TWideStringList;
begin
wsl := TWideStringList.Create(nil);
//...
if HasProperty(Self.Controls[i], "Caption") then begin
if Self.FindComponent(Self.Controls[i].Name) is TTntButton then
begin
with TTntButton(Self.FindComponent(Self.Controls[i].Name)) do
begin
wsl.Add(Self.Controls[i].Name+"="+Caption);
end;
end;
end;
//...
wsl.SaveUnicode := true;
wsl.SaveToFile("Captions.txt")
wsl.Free;

"is TComponent"использовать нельзя, т.к. тогда Caption читается как string, а не как WideString, и все unicode летит нафиг.

Может можно по-оптимальней? А то необходимо описывать каждый класс контролов отдельно, а класса типа TTntControl я вроде не нашел.


Юрий Зотов   (2002-12-10 23:38:00) [10]

> Kibitzer
:о)


Kibitzer   (2002-12-10 23:23:00) [11]


> MBo © (10.12.02 23:05)
> >Kibitzer
> Не нужно. protected члены класса, объявленного в том же
> модуле, доступны и так.

И правда. :))
Не думал, что так тоже считается :-/


MBo   (2002-12-10 23:05:00) [12]

>Kibitzer
Не нужно. protected члены класса, объявленного в том же модуле, доступны и так.


Kibitzer   (2002-12-10 23:00:00) [13]


> Юрий Зотов © (10.12.02 22:49)


> Тут надо немного иначе.

Где:
TFriendControl = class(TControl)
public
propertyCaption;
end;

;)


Юрий Зотов   (2002-12-10 22:49:00) [14]

> asmith (10.12.02 21:06)

Сами пробовали?

1. Свойство TControl.Caption - protected. Поэтому код даже не скомпилируется.
2. Контрол может лежать не на форме, а, например, на панели. Тогда в список myForm.Controls он не попадает.

Тут надо немного иначе.

type
TFriendControl = class(TControl);
...
for i := 0 to ComponentCount - 1 do
if Components[i] is TControl then
with TFriendControl(Components[i]) do
if Caption <> "" then ...


asmith   (2002-12-10 21:06:00) [15]

for nIndex := 0 to myForm.ControlCount - 1 do
SaveToFile(myForm.Controls[nIndex].Caption);


Наверх

Титульная страница Поиск, карта сайта Написать письмо