Как я могу вызвать процедуру, чье имя хранится в таблице, списке, и т.п.? Другими словами, я хочу сохранить имя процедуры в переменной и для ее вызова обращаться к значению этой переменной. Какие предложения?
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
- Подробности
- Родительская категория: Объектное ориентирование
- Категория: Разные вопросы
Страница 1 из 2