-
estra (04.10.11 10:26) [0]Всем доброго времени суток.
Нужна ваша помощь в поиске оптимального решения следующей задачи. Пишу редактор форм, аналогичный Delphi. Нужно реализовать поддержку копипаста (ctrl+c, ctrl+v). Решил пойти тем же путем, что и любимый компилятор, то есть по ctrl+c в буфер копируется текстовое представление компонента:function ComponentToString( Component: TComponent ): string;
var
BinStream: TMemoryStream;
StrStream: TStringStream;
begin
BinStream := TMemoryStream.Create;
try
StrStream := TStringStream.Create( Result );
try
BinStream.WriteComponent( Component );
BinStream.Seek( 0, soFromBeginning );
ObjectBinaryToText( BinStream, StrStream );
StrStream.Seek( 0, soFromBeginning );
Result := StrStream.DataString;
finally
StrStream.Free;
end;
finally
BinStream.Free
end;
end;
А вот с обратным действием возникли затруднения. Получить из строки компонент я могуprocedure StringToComponent( Component: TComponent; Value: string );
var
StrStream: TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create( Value );
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary( StrStream, BinStream );
BinStream.Position := 0;
BinStream.ReadComponent( Component );
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
но есть пара моментов, которые пока не получается оптимизировать.
1. Скопировав компонент в буфер и тут же вставляя его на форму я получу ошибку, т.к. компонент с таким именем на форме уже есть. Пока вижу решение в том, чтобы парсить строку, "вытаскивать" имя компонента, и менять его если компонент с таким именем на форме уже есть.
2. Передавать в качестве параметра Component нужно переменную того типа, строковое представление которого лежит сейчас в буфере. Значит опять нужно парсить строку, а дальше огромная вереница из if'ов.
Работать, конечно, такое будет, но хочется более изящного решения. Ведь в Delphi сотни компонентов, и можно кучу сторонних установить, и при этом ctrl+c/ctrl+v работают, значит есть универсальное решение. Пожалуйста, помогите его найти! -
function StringToComponent(const Value: string):TComponent; вар параметр или результат
var
StrStream: TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create( Value );
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary( StrStream, BinStream );
BinStream.Seek(0,soFromBeginning);
result:=BinStream.ReadComponent(nil);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end; -
estra (04.10.11 10:26)
2. Передавать в качестве параметра Component нужно переменную того типа, строковое представление которого лежит сейчас в буфере. Значит опять нужно парсить строку, а дальше огромная вереница из if'ов.
RegisterClass(TButton);
RegisterClass(TMemo);
и тек далее :) -
estra (04.10.11 11:32) [3]Slym
Спасибо, дело сдвинулось с места. Но снова вопрос.var
_Component: TComponent;
begin
_Component := StringToComponent( 'строковое представление компонента' );
// Далее нужно установить свойство Parent, чтобы отобразить компонент,
// а для этого нужно сделать приведение типа,
( _Component as TEdit ).Parent := ...
end;
Можно ли эту строчку ( ( _Component as TEdit ).Parent := ... ) унифицировать, иначе от кучи if'ов не уйти
if __Component is TEdit then
и так далее
if ( _Component as TEdit ).Parent := ... -
estra (04.10.11 11:42) [4]И владельца тоже нужно как то установить компоненту...
-
estra (04.10.11 12:17) [5]С владельцем разобрался - InsertComponent, теперь от кучи if'ов надо избавиться
-
c:=StringToComponent(s);
if c is TControl then
begin
Form1.InsertComponent(c);
Form1.InsertControl(TControl(c));
TControl(c).Top:=10;
end; -
estra (04.10.11 14:45) [7]Огромное спасибо, вопрос решен.
-
Клонирование компонента на примере TEdit// ---------------------------------------------------------------------------
// абстрактный класс, с виртуальной фунцией
class TClonable {
public:
virtual TClonable* Clone() = 0;
};
// ---------------------------------------------------------------------------
// множественное наследование, которое допустимо
// с использованием не VCL классов
class TClonableEdit : public TEdit, public TClonable {
public:
__fastcall TClonableEdit(TComponent *Owner) : TEdit(Owner) {
TForm *form = (TForm*)Owner;
Parent = form;
};
// ---------------------------------------------------------------------------
// конструктор копирования
// тут обратите внимание на TEdit(rhs.Owner)
// передаем в базовый класс VCL не rhs, а rhs.Owner
TClonableEdit(const TClonableEdit& rhs) : TEdit(rhs.Owner) {
Top = rhs.Top + 50;
Color = clRed;
Parent = rhs.Parent;
Text = "Клон";
};
// ---------------------------------------------------------------------------
// функция клонирования
TClonableEdit* Clone() {
return new TClonableEdit(*this);
};
};
// ---------------------------------------------------------------------------
class TEditWithLabel : public TClonableEdit {
public:
__fastcall TEditWithLabel(TComponent *Owner) : TClonableEdit(Owner) {
label = new TLabel(this);
label->Parent = Parent;
label->Caption = "Какая-то надпись";
label->Top = Top;
label->Left = Left + Width + 5;
};
TLabel *label;
// ---------------------------------------------------------------------------
// конструктор копирования
TEditWithLabel(const TEditWithLabel& rhs) : TClonableEdit(rhs) {
label = new TLabel(this);
label->Parent = rhs.label->Parent;
label->Caption = rhs.label->Caption;
label->Top = Top;
label->Left = rhs.label->Left;
};
// ---------------------------------------------------------------------------
// функция клонирования
TEditWithLabel* Clone() {
return new TEditWithLabel(*this);
};
};
// использование
TEditWithLabel *newEdit = new TEditWithLabel(this);
newEdit->Text = "Исходник";
// допустим что мы не знаем какой класс у newEdit,
// поэтому обращаемся к нему через TClonableEdit
TClonableEdit *clone = newEdit->Clone();
// но в результате получаем его копию в TEditWithLabel