Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2002.12.30;
Скачать: [xml.tar.bz2];

Вниз

Свойства не по умолчанию   Найти похожие ветки 

 
Дмитрий К.К.   (2002-12-17 09:30) [0]

Здравствуйте!
Задача такова: необходимо вывести в текстовый файл названия всех компонентов на форме.

Делаю следующим образом:
var
I: Integer;
F: TextFile;
begin
AssignFile(F, "components.txt");
try
Rewrite(F);
for I := 0 to ComponentCount-1 do
Writeln(F, Components[I].Name);
finally
CloseFile(F);
end;
end;

Но это только треть задачи. Помимо этого, нужно записать в файл:
1) экземплярами каких классов являются эти компоненты;
2) (и самое главное) вывести свойства (и события) этих компонентов, которые не равняются тем, что выставлены по умолчанию (то есть приблизительно то, что записывается в dfm).

Подскажите, пожалуйста, как сие реализовать.


 
MBo   (2002-12-17 09:32) [1]

2) Components[I].ClassName


 
Дмитрий К.К.   (2002-12-17 09:39) [2]

Спасибо... а относительно свойств?


 
stone   (2002-12-17 10:07) [3]

GetPropInfo


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

> Подскажите, пожалуйста, как сие реализовать.

Надо просто записать точно такой же DFM, который пишет сама Delphi, теми же самыми средствами, что и она.

const
FileName = "Form1.txt";

procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
begin
RegisterClass(TFormClass(ClassType));
for i := 0 to ComponentCount - 1 do
RegisterClass(TComponentClass(Components[i].ClassType))
end;

procedure TForm1.SaveButtonClick(Sender: TObject);
var
MemStream: TMemoryStream;
FileStream: TFileStream;
begin
MemStream := TMemoryStream.Create;
try
MemStream.WriteComponent(Self);
MemStream.Position := 0;
FileStream := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
try
ObjectBinaryToText(MemStream, FileStream);
finally
FileStream.Free
end
finally
MemStream.Free
end;
end;

procedure TForm1.LoadButtonClick(Sender: TObject);
var
FileStream: TFileStream;
MemStream: TMemoryStream;
Clone: TForm1;
begin
FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
FileStream.Position := 0;
MemStream := TMemoryStream.Create;
try
ObjectTextToBinary(FileStream, MemStream);
MemStream.Position := 0;
Clone := TForm1.CreateNew(nil);
try
MemStream.ReadComponent(Clone);
with Clone do
begin
Hide;
Name := "Clone";
Caption := Name;
SetBounds(Left + 10, Top + 10, Width + 50, Height + 50);
ShowModal
end
finally
Clone.Free
end
finally
MemStream.Free
end
finally
FileStream.Free
end
end;


 
han_malign   (2002-12-17 10:27) [5]

примерно так, в хелпе я ничего не нашел так-что открывай Delphi\Source\Vcl\TypeInfo.pas - и разбирайся

uses TypeInfo;
.........
var numProp: Integer;
PropList: PPropList;
.........
numProp:=GetPropList(Components[i].TypeInfo,[tkUnknown..tkDynArray],nil);
GetMem(PropList,sizeof(PPropInfo)*numPorp);
GetPropList(Components[i].TypeInfo,[tkUnknown..tkDynArray],PropList);
for i:=0 to numProp do with PropList[i]^ do begin //TPorpInfo

end;

З.Ы. А на самом деле выдираешь эту самую GetPropList из TypeInfo.pas, убираешь оттуда фильтрацию по типу - и вперед - это как раз то что тебе нужно.


 
Юрий Зотов   (2002-12-17 10:32) [6]

Забыл добавить объявление формы:

TForm1 = class(TForm)
Edit1: TEdit;
SaveButton: TButton;
LoadButton: TButton;
procedure SaveButtonClick(Sender: TObject);
procedure LoadButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

Меняя текст в Edit1 между нажатиями Save и Load, можно убедиться, что клон создается именно из файла.


 
han_malign   (2002-12-17 10:48) [7]

тогда уж проще - RxLib.RX Tools.FormStorage


 
Дмитрий К.К.   (2002-12-17 11:13) [8]

Юрий, спасибо... но немного не то...

Нужно не именно то, что пишет сама среда в dfm, а свой порядок записи:

AssignFile(F, SavFileName);
try
Rewrite(F);
for I := 0 to ComponentCount - 1 do
begin
Writeln(F, Components[I].Name + ": " + Components[I].ClassName);

...

Writeln(F, "-----");
end;
finally
CloseFile(F);
end;

Там, где многоточие, нужно записать то, что изменено в свойствах компонентов при редактировании в Инспекторе объектов (другими словами, что отличается от выставляемого по умолчанию).
Все это нужно для того, чтобы затем написать одну общую процедуру в редакторе кода (то есть Button1.Caption := "Save" и т.д.).


 
Юрий Зотов   (2002-12-17 14:52) [9]

> нужно записать то, что изменено в свойствах компонентов...
> ...другими словами, что отличается от выставляемого по
> умолчанию.

Именно так и поступает Delphi. Именно так и работает пример.


 
Дмитрий К.К.   (2002-12-17 15:18) [10]

Юрий, не смею спорить, что так и работает Ваш пример (поскольку сам его проверял).
Но... то, как переводит бинарник в строку метод ObjectBinaryToText, кажется немного не тем, что надо...

object Panel1: TPanel
Left = 0
Top = 374
Width = 611
Height = 41
Align = alBottom
BevelInner = bvLowered

и т.д.

Совсем другое дело - следующее представление:

Panel1.Left := 0;
Panel1.Top := 374;
Panel1.Width := 611;
Panel1.Height := 41;
Panel1.Align := alBottom;
Panel1.BevelInner := bvLowered;


Поэтому нет ли других альтернатив Вашему методу (например, тех, что предлагает han_malign)?


 
Юрий Зотов   (2002-12-17 17:42) [11]

Ну, во-первых, это метод не мой, а, скорее, Борландовский. Я лишь повторил в явном виде то же самое, что делает сама Delphi, когда пишет свои DFM.

Во-вторых, альтернатива, конечно, есть - именно то, о чем говорил han_malign. Использование RTTI для "ручного" сохранения и чтения. Если Вам это кажется лучше - никто не запрещает. Но советую сначала посмотреть исходники TStream.WriteComponent (и ReadComponent). Вы убедитесь, что код там совсем не детский - а ведь Вам придется сделать примерно то же самое.

Так что выбор за Вами - либо тот формат, который Вам больше нравится, либо простота и надежность кода. Я бы выбрал второе - тем более, что родной Дельфишный формат не менее прост и понятен, чем тот, который Вы привели (а по объему текста еще и короче). К тому же, он универсален для любых компонентов.


 
Vcoder   (2002-12-17 19:14) [12]

Может конечно это и не то, но мне вот что пришло на ум:
Записать файл по типу dfm (как предложил Юрий Зотов), а затем уже ЕГО приводить в читабельный вид.


 
Дмитрий К.К.   (2002-12-17 19:54) [13]


> Я бы выбрал второе - тем более, что родной Дельфишный формат
> не менее прост и понятен, чем тот, который Вы привели (а
> по объему текста еще и короче).


И здесь спорить не буду. Однако формат "текстовый dfm", записанный в редакторе коде, естественно, не примет к рассмотрению компилятор Delphi.
Моя задача - выжать из наполненной компонентами формы все, что можно (и нужно), а затем в пустой форме в обработчике события OnCreate усё ето воссоздать. Можно, конечно, загрузить все эти компоненты из внешнего файла, сохраненного при помощи Борландовского метода, но требуется реализовать другим способом.


 
Бурундук   (2002-12-17 20:16) [14]

Вот пример перебора всех published св-в,
нашёл в каких-то своих извращениях:
(писать что-то конкретное по твоей теме мне облом -
хлопотно это больно)

Разобраться, думаю, можно.


procedure UpgradeComponent(OldCmp: TComponent; NewCmpClass: TComponentClass);
var NewCmp: TComponent;
CmpName: string;
Cls: TClass;
i: Integer;

PropCnt: Integer;
PropList: PPropList;
PropInfo: PPropInfo;

function IsField(PropProc: Pointer): Boolean;
type ba = array[0..3]of Byte;
begin
Result := ba(PropProc)[3] > $FE;
end;
begin
if not NewCmpClass.InheritsFrom(OldCmp.ClassType) then
raise Exception.CreateFmt("Cannot upgrade %s to %s",
[OldCmp.ClassName, NewCmpClass.ClassName]);

NewCmp := NewCmpClass.Create(OldCmp.Owner);

PropCnt := GetTypeData(OldCmp.ClassInfo)^.PropCount;
GetMem(PropList, PropCnt*SizeOf(Pointer));

try
GetPropInfos(OldCmp.ClassInfo, PropList);

for i := 0 to PropCnt-1 do
begin
PropInfo := PropList^[i];
if (PropInfo^.Name <> "Name") then
begin
if PropInfo^.PropType^^.Kind = tkMethod then
SetMethodProp(NewCmp, PropInfo,
GetMethodProp(OldCmp, PropInfo))
else if PropInfo^.PropType^^.Kind = tkClass then
begin
Cls := GetTypeData(PropInfo^.PropType^).ClassType;
if (PropInfo^.Name = "Constraints") then
// По непонятной причине свойство
// property Constraints: TSizeConstraints read FConstraints write FConstraints;
// производит запись прямо в поле, а не через Set-метод + Assign
// Поэтому приходится делать обходной маневр.
TPersistent(GetObjectProp(NewCmp, PropInfo)).Assign
(TPersistent(GetObjectProp(OldCmp, PropInfo)))
else
begin
SetObjectProp(NewCmp, PropInfo,
GetObjectProp(OldCmp, PropInfo));
end;
end
else
SetPropValue(NewCmp, PropInfo^.Name, GetPropValue(OldCmp, PropInfo^.Name));
end;
end;
finally
FreeMem(PropList, PropCnt*SizeOf(Pointer));
end;

CmpName := OldCmp.Name;
if OldCmp is TControl then
with TControl(OldCmp) do
begin
TControl(NewCmp).Parent := Parent;
TControl(NewCmp).Visible := Visible;
TControl(NewCmp).Enabled := Enabled;
Hide;
end;

OldCmp.Free;
NewCmp.Name := CmpName; // -> NewCmp.SetReference
end;


Но учти:
Св-ва типа ссылки на компоненты (не на объекты-потомки TPersistent, принадлежащие объекту) ты получаешь из RTTI
в виде указателя, а сохранять их надо как имена
(ну не получится иначе) - а потом, соответственно, по имени
находить.

И то же самое для tkMethod - обработчиков событий.

Если есть желание разбираться с десятком частных случаев -
что ж, флаг тебе в руки, typinfo.pas в зубы и вперёд.




Но, чесно говоря, я не понимаю, чем тебе стандартное сохранение/чтение не нравится.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2002.12.30;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.62 MB
Время: 0.045 c
1-99109
korvet
2002-12-18 09:19
2002.12.30
Удобный редактор текста


3-98965
Goobit
2002-12-09 13:19
2002.12.30
Лог изменений в TClientDataSet


6-99213
dimonf
2002-10-31 18:57
2002.12.30
Какой компанент использовать для работы на ниском уровне с SMTP.


1-99068
Kosmach
2002-12-15 20:49
2002.12.30
Обработка событий у динамически созданных объектов


1-99127
V_Pavel
2002-12-18 11:09
2002.12.30
Вопрос по Excel





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский