سؤال

كيف يمكنني إنشاء مكون في وقت التشغيل ثم العمل معه (تغيير الخصائص، وما إلى ذلك)؟

هل كانت مفيدة؟

المحلول

يعتمد ذلك على ما إذا كان مكونًا مرئيًا أو غير مرئي.المبدأ هو نفسه، ولكن هناك بعض الاعتبارات الإضافية لكل نوع من المكونات.

للمكونات غير المرئية

var
  C: TMyComponent;
begin
  C := TMyComponent.Create(nil);
  try
    C.MyProperty := MyValue;
    //...
  finally
    C.Free;
  end;
end;

للمكونات البصرية:

في الأساس، يتم إنشاء المكونات المرئية بنفس طريقة إنشاء المكونات غير المرئية.ولكن عليك تعيين بعض الخصائص الإضافية لجعلها مرئية.

var
  C: TMyVisualComponent;
begin
  C := TMyVisualComponent.Create(Self);
  C.Left := 100;
  C.Top := 100;
  C.Width := 400;
  C.Height := 300;
  C.Visible := True;
  C.Parent := Self; //Any container: form, panel, ...

  C.MyProperty := MyValue,
  //...
end;

بعض التفسيرات للكود أعلاه:

  • من خلال تعيين مالك المكون (معلمة المنشئ)، يتم تدمير المكون عندما يتم تدمير النموذج الخاص به.
  • وضع Parent الخاصية تجعل المكون مرئيًا.إذا نسيت ذلك، فلن يتم عرض المكون الخاص بك.(من السهل أن تفوت ذلك :))

إذا أردت العديد من المكونات يمكنك أن تفعل الشيء نفسه كما هو مذكور أعلاه ولكن في حلقة:

var
  B: TButton;
  i: Integer;
begin
  for i := 0 to 9 do
  begin
    B := TButton.Create(Self);
    B.Caption := Format('Button %d', [i]);
    B.Parent := Self;
    B.Height := 23;
    B.Width := 100;
    B.Left := 10;
    B.Top := 10 + i * 25;
  end;
end;

سيؤدي هذا إلى إضافة 10 أزرار على الحد الأيسر للنموذج.إذا كنت تريد تعديل الأزرار لاحقًا، فيمكنك تخزينها في القائمة.(قائمة المكونات هو الأنسب، ولكن قم أيضًا بإلقاء نظرة على المقترحات الواردة من التعليقات على هذه الإجابة)

كيفية تعيين معالجات الأحداث:

يجب عليك إنشاء طريقة معالج الحدث وتعيينها إلى خاصية الحدث.

procedure TForm1.MyButtonClick(Sender: TObject);
var
  Button: TButton;
begin
  Button := Sender as TButton; 
  ShowMessage(Button.Caption + ' clicked');
end;

B := TButton.Create;
//...
B.OnClick := MyButtonClick;

نصائح أخرى

لتبسيط عملية إنشاء مكون وقت التشغيل، يمكنك استخدام خبراء.

  1. قم بإنشاء مكون (أو المزيد من المكونات) بشكل مرئي وقم بتعيين خصائصه.
  2. حدد مكونًا واحدًا أو أكثر وقم بتنفيذ GExperts، Components to Code.
  3. الصق الكود الذي تم إنشاؤه في التطبيق الخاص بك.
  4. قم بإزالة المكون (المكونات) من مصمم النموذج المرئي.

مثال (رمز إنشاء TButton الذي تم إنشاؤه بهذه الطريقة):

var
  btnTest: TButton;

btnTest := TButton.Create(Self);
with btnTest do
begin
  Name := 'btnTest';
  Parent := Self;
  Left := 272;
  Top := 120;
  Width := 161;
  Height := 41;
  Caption := 'Component creation test';
  Default := True;
  ParentFont := False;
  TabOrder := 0;
end;

وأود فقط أن أضيف أن عند إضافة عناصر تحكم حيوي ... انها فكرة جيدة لإضافتها إلى قائمة الكائنات (TObjectList) كما هو مقترح في <1> من جانبDespatcher.

procedure Tform1.AnyButtonClick(Sender: TObject);
begin
  If Sender is TButton then
  begin
    Case Tbutton(Sender).Tag of 
    .
    .
    .
// Or You can use the index in the list or some other property 
// you have to decide what to do      
// Or similar :)
  end;
end;

procedure TForm1.BtnAddComponent(Sender: TObJect)
var
  AButton: TButton;
begin
  AButton := TButton.Create(self);
  Abutton. Parent := [Self], [Panel1] [AnOther Visual Control];
  AButton.OnClick := AnyButtonClick;
// Set Height and width and caption ect.
  .
  .
  . 
  AButton.Tag := MyList.Add(AButton);
end;

تحتاج إلى إضافة وحدة "Contnrs 'الى قائمة استخدامات الخاصة بك. أي بمعنى System.Contnrs.pas وحدة حاويات قاعدة ويمكنك الحصول على العديد من القوائم الكائن. أقترح استخدام TObjectList لكل نوع من أنواع الرقابة التي تستخدمها منها مثلا.

Interface
 Uses Contnrs;
Type
 TMyForm = class(TForm)
private
   { Private declarations }
public
   { Public declarations }
end;
 Var
  MyForm: TMyForm;
  checkBoxCntrlsList: TObjectList; //a list for the checkBoxes I will createin a TPanel
  comboboxCntrlsList: TObjectList; //a list of comboBoxes that I will create in some Form Container

وهذا يسمح لك بسهولة التلاعب / إدارة كل عنصر تحكم كما سوف تعرف ما هو نوع من الرقابة هو منها مثلا.

Var comboBox: TComboBox;
I: Integer;

begin
 For I = 0 to comboboxCntrlsList.Count -1 do // or however you like to identify the control you are accessing such as using the tag property as @Despatcher said
   Begin
    comboBox := comboboxCntrlsList.Items[I] as TComboBox;
    ...... your code here
   End;
end;

وهذا يسمح لك بعد ذلك إلى استخدام الأساليب والخصائص التي تحكم لا ننسى لإنشاء TObjectLists، ربما في شكل خلق الحدث ...

checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
<اقتباس فقرة>   

ولكن اذا كنت لا تعرف بالتأكيد كم مكونات أريد إنشاء، على سبيل المثال إذا كان يعتمد على قرار المستخدم. فكيف أعلن مكونات حيوي؟

تم اقترح الجواب - أسهل طريقة هي قائمة الكائنات (مكونات). TObjectList هو أبسط لاستخدام (في contnrs وحدة). قوائم كبيرة!

  In Form1 Public
  MyList: TObjectList;
  procedure AnyButtonClick(Sender: TObject); 

و// يمكنك الحصول على أكثر تطورا وتعلن // TNotifyevents والتنازل عنها ولكن يسمح يبقيه بسيط :)   .   .   .

procedure Tform1.AnyButtonClick(Sender: TObject);
begin
  If Sender is TButton then
  begin
    Case Tbutton(Sender).Tag of 
    .
    .
    .
// Or You can use the index in the list or some other property 
// you have to decide what to do      
// Or similar :)
  end;
end;

procedure TForm1.BtnAddComponent(Sender: TObJect)
var
  AButton: TButton;
begin
  AButton := TButton.Create(self);
  Abutton. Parent := [Self], [Panel1] [AnOther Visual Control];
  AButton.OnClick := AnyButtonClick;
// Set Height and width and caption ect.
  .
  .
  . 
  AButton.Tag := MyList.Add(AButton);
end;

ويمكن أن تحتوي قائمة كائن أي كائن البصرية أم لا ولكن التي تمنحك النفقات المضافة لفرز العناصر التي هي التي - الأفضل أن يكون القوائم ذات الصلة إذا كنت تريد متعددة التحكم الديناميكي على لوحات مماثلة على سبيل المثال

ملحوظة: مثل المعلقين الآخرين ربما أكون قد الإفراط في تبسيط الإيجاز ولكن أرجو أن شركة جنرال الكتريك هذه الفكرة. كنت في حاجة الى آلية لإدارة كائنات أخرى يتم إنشاؤها وقوائم ممتازة لهذه الاشياء.

وخلال البحث على "إنشاء نموذج دلفي باستخدام قالب يستند إلى XML"، وأجد شيئا لافتا مفيدة من RTTI واستخدام أدوات مفتوحة API (ToolsApi.pas على ما أظن). إلقاء نظرة على واجهات في الوحدة.

وتخفيف جدا. استدعاء إنشاء. مثال:

procedure test
var
  b : TButton;
begin
  b:=TButton.Create(nil);
  b.visible:=false;
end;

وهذا يخلق عنصر (TButton هو عنصر) في وقت التشغيل وبتعيين الخاصية مرئية.


لالمنشئ: تمرير شيء إذا كنت ترغب في إدارة الذاكرة نفسك. تمرير مؤشر مكون آخر إذا كنت تريد أن يكون دمرت عندما يتم تدمير العنصر الآخر.

وبعض مكونات تجاوز أسلوب "المحملة. لن يتم استدعاء هذا الأسلوب تلقائيا إذا قمت بإنشاء مثيل في وقت التشغيل. وسوف يطلق عليه دلفي عند تحميل من ملف النموذج (DFM) غير كاملة.

إذا يحتوي على طريقة رمز التهيئة، التطبيق الخاص بك قد تظهر سلوك غير متوقع عندما تم إنشاؤها في وقت التشغيل. في هذه الحالة، معرفة ما اذا كان قد استخدم الكاتب مكون هذا الأسلوب.

إذا كنت عش الفوز التحكم في صناديق المجموعة / صفحة التحكم / الخ ...، وأعتقد أنه من المفيد أن يكون مربع المجموعة الأم أيضا أن يكون المالك. لقد لاحظت انخفاضا حادا في أوقات قريبة النافذة عند القيام بذلك، بدلا من الاضطرار المالك يكون دائما هو النموذج الرئيسي.

هذا مثال على كيفية محاكاة علامة الزر على Evernote

unit Unit7;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, CHButton, Vcl.ExtCtrls, RzPanel, CHPanel, RzCommon,RzBmpBtn, Vcl.StdCtrls;

type
  // This is panel Button
  TButtonClose = class (TRzPanel)
   CloseButton : TRzBmpButton;
   procedure CloseButtonClick(Sender: TObject);
   procedure CloseButtonMouseEnter(Sender: TObject);
   procedure MouseDown(Sender: TObject; Button: TMouseButton;
             Shift: TShiftState; X, Y: Integer);
   procedure MouseUp(Sender: TObject; Button: TMouseButton;
             Shift: TShiftState; X, Y: Integer);
public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
end;

TForm7 = class(TForm)
   CHButton1: TCHButton;
   RzPanel1: TRzPanel;
   RzBmpButton1: TRzBmpButton;
   procedure CHButton1Click(Sender: TObject);
   procedure RzBmpButton1Click(Sender: TObject);
   procedure RzPanel1MouseDown(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
   procedure RzPanel1MouseUp(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
   procedure RzPanel1MouseEnter(Sender: TObject);
   procedure RzBmpButton1MouseEnter(Sender: TObject);
   procedure FormMouseEnter(Sender: TObject);
   procedure FormCreate(Sender: TObject);
private
  { Private declarations }
public
  { Public declarations }
end;

var
  Form7: TForm7;
  MyCloseButton : TButtonClose;

implementation

{$R *.dfm}

// constructor for on the fly component created
constructor TButtonClose.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);

   // Set Events for the component
   Self.OnMouseEnter := Self.CloseButtonMouseEnter;
   Self.OnMouseDown := Self.MouseDown;
   Self.OnMouseUp := Self.MouseUp;
   Self.Height := 25;

   // Close button on top panel Button
   // Inherited from Raize Bitmap Button
   CloseButton := TRzBmpButton.Create(self);
   // Set On Click Event for Close Button
   CloseButton.OnClick := Self.CloseButtonClick;
   // Place Close Button on Panel Button
   CloseButton.Parent := self;
   CloseButton.Left := 10;
   CloseButton.Top := 5;
   CloseButton.Visible := False;
   // Setting the image for the button
   CloseButton.Bitmaps.Up.LoadFromFile(ExtractFilePath(Application.ExeName)+'\close.bmp');
end;

procedure TButtonClose.CloseButtonClick(Sender: TObject);
begin
   // Free the parent (Panel Button)
   TControl(Sender).Parent.Free;
end;

procedure TButtonClose.CloseButtonMouseEnter(Sender: TObject);
begin
   // Show the Close button
   CloseButton.Visible := True;
end;

procedure TButtonClose.MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
   // Emulate Button down state, since it is panel
   TRzPanel(Sender).BorderOuter := fsLowered;
end;

procedure TButtonClose.MouseUp(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
begin
   // Emulate Button up state, since it is panel
   TRzPanel(Sender).BorderOuter := fsRaised;
end;

destructor TButtonClose.Destroy;
begin
   inherited Destroy;
end;

procedure TForm7.FormCreate(Sender: TObject);
begin
   // Create Panel Button on the fly
   MyCloseButton := TButtonClose.Create(self);
   MyCloseButton.Caption := 'My Button';
   MyCloseButton.Left := 10;
   MyCloseButton.Top := 10;
   // Don't forget to place component on the form
   MyCloseButton.Parent := self;
end;

procedure TForm7.FormMouseEnter(Sender: TObject);
begin
   if Assigned(RzBmpButton1) then
      RzBmpButton1.Visible := False;

   // Hide when mouse leave the button
   // Check first if myCloseButton Assigned or not before set visible property
   if Assigned(MyCloseButton.CloseButton) then
      MyCloseButton.CloseButton.Visible := False;
end;

procedure TForm7.RzBmpButton1Click(Sender: TObject);
begin
   TControl(Sender).Parent.Free;
end;

procedure TForm7.RzBmpButton1MouseEnter(Sender: TObject);
begin
   RzBmpButton1.Visible := True;
end;

procedure TForm7.RzPanel1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  TRzPanel(Sender).BorderOuter := fsLowered;
end;

procedure TForm7.RzPanel1MouseEnter(Sender: TObject);
begin
   RzBmpButton1.Visible := True;
end;

procedure TForm7.RzPanel1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
   TRzPanel(Sender).BorderOuter := fsRaised;
end;

procedure TForm7.CHButton1Click(Sender: TObject);
begin
   FreeAndNil(Sender);
end;

end.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top