Как я могу вызвать процедуру, чье имя хранится в таблице, списке, и т.п.? Другими словами, я хочу сохранить имя процедуры в переменной и для ее вызова обращаться к значению этой переменной. Какие предложения?

 

Code:

unit ProcDict;

 

interface

 

type MyProc = procedure(s: string);

 

procedure RegisterProc(procName: string; proc: MyProc);

procedure ExecuteProc(procName: string; arg: string);

 

implementation

 

uses Classes;

var ProcDict: TStringList;

 

procedure RegisterProc(procName: string; proc: MyProc);

begin

ProcDict.AddObject(procName, TObject(@proc));

end;

 

procedure ExecuteProc(procName: string; arg: string);

var

index: Integer;

begin

index := ProcDict.IndexOf(ProcName);

ifindex >= 0then

MyProc(ProcDict.objects[index])(arg);

// Можно вставить обработку исключительной ситуации - сообщение об ошибке

end;

 

initialization

ProcDict := TStringList.Create;

ProcDict.Sorted := true;

finalization

ProcDict.Free;

end.

 

 

 

вы могли бы создать StringList как показано ниже:

 

Code:

StringList.Create; StringList.AddObject('Proc1',@Proc1);

StringList.AddObject('Proc2',@Proc2);

 

 

и затем реализовать это в вашей программе:

 

Code:

var

myFunc: procedure;

begin

if Stringlist.indexof(S) = -1then

MessageDlg('Не понял процедуру ' + S, mtError, [mbOk], 0)

else

begin

@myFunc := Stringlist.Objects[Stringlist.indexof(S)];

myFunc;

end;

 

 

 

RAM

 

Взято из Советов по Delphi от Валентина Озерова

Сборник Kuliba

 

Code:

var F: procedure(x, y: double);

 

@F := GetProcAddress(hDLL, 'SOMEPROC');

F(3, 4);

 

 

Ключом здесь является использование оператора @, располагаемого с левой части процедурной переменной. Он говорит компилятору: "Не волнуйтесь здесь о совместимости типов, просто присвойте полученный в правой части выражения адрес переменной в левой части выражения (и процедурные переменные являются переменными-указателями).

 

- Peter Below

 

Взято из Советов по Delphi от Валентина Озерова

Сборник Kuliba

При создании визуальных контролов в runtime, важным моментом является назначение родительских свойств и использование метода SetBounds, чтобы этот контрол стал видимы.

 

Code:

type

TForm1 = class(TForm)

protected

MyLabel: TLabel;

procedure LabelClick(Sender: TObject);

procedure CreateControl;

end;

 

procedure TForm1.LabelClick(Sender: TObject);

begin

(Sender asLabel).Caption := ...

end;

 

procedure TForm1.CreateControl;

var

ALeft, ATop, AWidth, AHeight: Integer;

begin

ALeft := 10;

ATop := 10;

AWidth := 50;

AHeight := 13;

MyLabel := TLabel.Create(Self);

MyLabel.Parent := Self;

MyLabel.Name:='LabelName';

MyLabel.SetBounds(ALeft, ATop, AWidth, AHeight);

MyLabel.OnClick := LabelClick;

end;

 

 

 

Взято из https://forum.sources

TObject - "корневой" объект.

 

TClass определен как Class of TObject. Переменная Class НЕ является указателем на экземпляр объекта. Это указатель на *ТИП* объекта Class.

Code:

var

Obj1: TWinControl;

Class1: classof TWinControl;

 

Class1 := TWinControl - правильное присваивание. Мы не распределяем память, у нас нет экземпляра TWinControl, мы не можем вызвать Class1.OnClick.

 

Class1 - это *тип* TWinControl с тем же контекстом использования, что и "TWinControl".

 

Поскольку мы можем использовать TWinControl.Create, то также мы можем использовать и Class1.Create, при этом создавая новый экземпляр TWinControl.

 

С тех пор как TEdit - наследник TWinControl, Class1 := TEdit правильное присваивание и Class1.Create создает экземпляр TEdit.

 

Если у меня имеется переменная Obj2: TWinControl, и даже если я присвоил экземпляр TListbox Obj2, я не могу ссылаться на Obj2.Items, поскольку Obj2 определен как TWinControl, а TWinControl не имеет свойства Items.

 

Те же характеристики верны и для Class1. Class1 определен как Class of TWinControl, поэтому они имеют общий конструктор, определенный в классе TWinControl.

 

Это не пугает меня при создании дополнительных типов:

 

Code:

TMyObj1 = class(TEdit)

constructor CreateMagic; virtual;

end;

 

TMyObj2 = class(TMyObj1)

constructor CreateMagic; override;

end;

 

TMyClass = classof TMyObj;

 

var

MyObj1: TMyObj1;

MyObj2: TMyObj2;

 

function MakeAnother(AClass: TMyClass): TMyObj1;

begin

Result := AClass.CreateMagic;

end;

 

begin

MyObj2 := TMyObj2.CreateMagic;

MyObj1 := MakeAnother(MyObj2.ClassType);

end.

 

 

 

 

Взято из Советов по Delphi от Валентина Озерова

Сборник Kuliba

Code:

{

Здесь пpоцедypа CreateClone, котоpая кpеатит компонентy ОЧЕHЬ ПОХОЖУЮ на

входнyю. С такими же значениями свойств. Пpисваивается все, кpоме методов.

}

function CreateClone(Src: TComponent): TComponent;

var

F: TStream;

begin

F := nil;

try

F := TMemoryStream.Create;

F.WriteComponent(Src);

RegisterClass(TComponentClass(Src.ClassType));

F.Position := 0;

Result := F.ReadComponent(nil);

finally

F.Free;

end;

end;

Примечание: внесение изменений в VCL не поддерживается Borland или Borland Developer Support.

-Но если Вы решили сделать это...

Изменения в код VCL никогда не должны вносится в секцию "interface" модуля - только в секцию "implimentation". Наиболее безопасный способ внести изменения в VCL - создать новый каталог названный "исправленный VCL". Скопируйте файл VCL который Вы хотите изменить в этот каталог. Внесите изменения (лучше прокомментировать их) в этот файл. Затем добавьте путь к Вашему каталогу "исправленный VCL" в самое начало "library path". Перезапустите Delphi/C++ Builder и перекомпилируйте Ваш проект. "library path" можно изменить в меню:

 

Delphi 1 : Options | Environment | Library

Delphi 2 : Tools | Options | Library

Delphi 3 : Tools | Environment Options | Library

Delphi 4 : Tools | Environment Options | Library

C++ Builder : Options | Environment | Library

Создатькопиюобъектав Delphi оченьпросто. Конвертируемобъектвтекст, азатем - обратно. Приэтомбудутпродублированывсесвойства, кромессылокнаобработчикисобытий. Дляпреобразованиякомпонентавфайлиобратнонампонадобятсяфункциипотоков WriteComponent(TComponent) и ReadComponent(TComponent). Приэтомвпотокзаписываетсядвоичныйресурс. Последнийспомощьюфункции ObjectBinaryToText можнопреобразоватьвтекст.
Создадимнаихосновефункциипреобразования:

Code:

function ComponentToString(Component: TComponent): string;

var

ms: TMemoryStream;

ss: TStringStream;

begin

ss := TStringStream.Create(' ');

ms := TMemoryStream.Create;

try

ms.WriteComponent(Component);

ms.position := 0;

ObjectBinaryToText(ms, ss);

ss.position := 0;

Result := ss.DataString;

finally

ms.Free;

ss.free;

end;

end;

 

procedure StringToComponent(Component: TComponent; Value: string);

var

StrStream:TStringStream;

ms: TMemoryStream;

begin

StrStream := TStringStream.Create(Value);

try

ms := TMemoryStream.Create;

try

ObjectTextToBinary(StrStream, ms);

ms.position := 0;

ms.ReadComponent(Component);

finally

ms.Free;

end;

finally

StrStream.Free;

end;

end;

Спомощьюпарыэтихфункциймыможемпреобразоватьлюбойкомпонентвтекст, азатемпроинициализироватьдругойкомпоненттогожеклассаэтимиданными.
Нижеприведенресурсформысоднойкнопкойитекстобработчиканажатиянаэтукнопку.

Code:

object Form1: TForm1

Left = 262

Top = 129

Width = 525

Height = 153

Caption = 'Form1'

Color = clBtnFace

Font.Charset = DEFAULT_CHARSET

Font.Color = clWindowText

Font.Height = -11

Font.Name = 'MS Sans Serif'

Font.Style = []

OldCreateOrder = False

Scaled = False

PixelsPerInch = 96

TextHeight = 13

object Button1: TButton

Left = 16

Top = 32

Width = 57

Height = 49

Caption = 'Caption'

TabOrder = 0

OnClick = Button1Click

end

end

 

procedure TForm1.Button1Click(Sender: TObject);

var

Button: TButton;

OldName: string;

begin

Button := TButton.Create(self);

 

//...сохраняем имя компонента

OldName := (Sender as TButton).Name;

 

//...стираем имя компонента, чтобы избежать конфликта имен.

//...После этого Button1 станет = nil.

(Sender as TButton).Name := '';

 

//...преобразуем в текст и обратно

StringToComponent( Button, ComponentToString(Sender as TButton) );

 

//...дадим компоненту уникальное(?) имя

Button.Name := 'Button' + IntToStr(random(1000));

 

//...вернем исходному компоненту имя.

//...После этого Button1 станет снова указывать на объект.

(Sender as TButton).Name := OldName;

 

//...размещаем новую кнопку справа от исходной

Button.parent := self;

Button1.Tag := Button1.Tag + 1;

Button.Left := Button.Left + Button.Width * Button1.Tag + 1;

end;

Приведенныйметоднедублируетуказателинаобработчикисобытий. Однако, еслитакимобразомдублироватьформы, товседочерниекомпонентыивсеобработчикисохранятся.

составлениестатьи: АндрейЧудин, ЦПРТДБиблио-Глобус

 

Взято из  https://delphi.chertenok

Code:

type

ISelfDestroy = interface;

//forget about GUID, if you are not using COM

 

TSelfDestroy = class(TInterfacedObject, ISelfDestroy)

private

FObject: TObject;

public

constructor Create(AObject: TObject);

destructor Destroy; override;

end;

 

implementation

 

constructor TSelfDestroy.Create(AObject: TObject);

begin

FObject := AObject;

end;

 

destructor TSelfDestroy.Destroy;

begin

FreeAndNil(FObject);

inherited;

end;

 

 

// So when you use, just do like this...

 

procedure TForm1.Button1Click(Sender: TObject);

var

MyObject: TMyObject;

SelfDestroy: TSelfDestroy;

begin

MyObject := TMyObject.Create;

SelfDestroy := TSelfDestroy.Create(MyObject);

// The MyObject will free automatically as soon as TSelfDestroy

// goes out of scope.

// Carry on your code here...

end;

 

 

 

Взято с сайтаhttps://www.swissdelphicenter.ch/en/tipsindex

В общем случае, утверждение "Destination := Source" не идентично утверждению "Destination.Assign(Source)".

 

Утверждение "Destination := Source" принуждает Destination ссылаться на тот же объект, что и Source, а "Destination.Assign(Source)" копирует содержание объектных ссылок Source в объектные ссылки Destination.

 

Если Destination является свойством некоторого объекта (тем не менее, и свойство не является ссылкой на другой объект, как, например, свойство формы ActiveControl, или свойство DataSource элементов управления для работы с базами данных), тогда утверждение "Destination := Source" идентично утверждению "Destination.Assign(Source)". Это объясняет, почему LB.Items := MemStr работает, когда MemStr := LB.Items нет.

 

Взято из Советов по Delphi от Валентина Озерова

Сборник Kuliba

Вначале сделаем интерфейс для нашего объекта:

 

Code:

type

IAutoClean = interface

['{61D9CBA6-B1CE-4297-9319-66CC86CE6922}']

end;

 

TAutoClean = class(TInterfacedObject, IAutoClean)

private

FObj: TObject;

public

constructor Create(AObj: TObject);

destructor Destroy; override;

end;

 

implementation

 

constructor TAutoClean.Create(AObj: TObject);

begin

FObj := AObj;

end;

 

destructor TAutoClean.Destroy;

begin

FreeAndNil(FObj);

inherited;

end;

 

А теперь будем использовать его вместо объекта:

 

Code:

procedure TForm1.Button1Click(Sender: TObject);

var

a: IAutoClean;

//must declare as local variable, so when this procedure finished, it's out of scope

o: TOpenDialog; //any component

begin

o := TOpenDialog.Create(self);

a := TAutoClean.Create(o);

if o.Execute then

ShowMessage(o.FileName);

end;

 

 

 

 

 

Взято с Delphi Knowledge Base: https://www.baltsoft

...чтобы сгруппировать свойства наподобие Font, вам необходимо создать наследника (подкласс) TPersistent. Например:

 

Code:

TBoolList = class(TPersistent)

private

FValue1: Boolean;

FValue2: Boolean

published

property Value1: Boolean read FValue1 write FValue1;

property Value2: Boolean read FValue2 write FValue2;

end;

 

 

Затем, в вашем новом компоненте, для этого подкласса необходимо создать ivar. Чтобы все работало правильно, вам необходимо перекрыть конструктор.

 

Code:

TMyPanel = class(TCustomPanel)

private

FBoolList: TBoolList;

public

constructor Create( AOwner: TComponent ); override;

published

property BoolList: TBoolList read FBoolList write FBoolLisr;

end;

 

Затем добавьте следующий код в ваш конструктор:

 

Code:

constructor TMyPanel.Create( AOwner: TComponent );

begin

inherited Create( AOwner );

FBoolList := TBoolList.Create;

end;

 

 

 

 

 

Взято с https://delphiworld.narod