如何为某种类型的所有实例实现我自己的自定义属性编辑器? [英] How can I implement my own custom property editor for all instances of a certain type?
问题描述
我遵循了一些关于创建自定义属性编辑器对话框的教程,但是涉及的内容太多,我无法让它正常工作.我想要完成的是一个带有日期选择器(日历)、时间选择器以及确定和取消按钮的自定义表单.表单完全没有问题,但是我将如何实现它,以便我可以在某种类型的任何组件中发布属性,并带有一个按钮来启动属性编辑器?
I have followed a few tutorials on creating a custom property editor dialog, but there are so many things involved that I could not get it to work right. What I am trying to accomplish is a custom form with a date picker (calendar), a time picker, and OK and Cancel buttons. The form is no problem at all, but how would I go about implementing this so that I can publish a property in any component of a certain type with a button to launch the property editor?
我想完全覆盖 TDateTime
类型并将我的自定义编辑器放在它的位置,因此无论 TDateTime
发布并在对象检查器中可见,我都可以使用此编辑器在同一窗口中同时修改日期和时间.
I would like to completely override the TDateTime
type and put my custom editor in its place, so wherever a TDateTime
is published and visible in the Object Inspector, I can use this editor to modify both date and time together in the same window.
问题在于有关创建自定义属性编辑器的文档很差,尽管有些资源非常详尽,但它们涉及的功能过于详细,并且缺乏对最常见场景的重点.
The problem is that the documentation on creating a custom property editor is poor and although some resources are very thorough, they go into too much detail of the capabilities and lack getting to the point on the most common scenarios.
推荐答案
我不想在这里问这个问题并希望有人为我回答,所以我自己做了研究以解决我的问题,我想分享参与这个迷你项目的独特体验,我相信其他人也会对同样的事情感到沮丧.
I did not want to ask this question here and expect anyone to answer it for me, so I did the research myself to solve my issues and I would like to share the unique experience involved in this mini project, as I'm sure others are frustrated with the same thing.
自定义属性编辑器、对话框和组件编辑器有许多不同的可能性.这尤其需要 TDateTimeProperty
后代.这将允许您直接在 Object Inspector 中以纯文本 (String) 形式编辑属性的值,同时保持 DateTime 格式.
There are many different possibilities with custom property editors, dialogs, and component editors. This in particular would call for a TDateTimeProperty
descendant. This would allow you to be able to edit the value of the property directly in the Object Inspector as plain text (String) while keeping the DateTime formatting.
我假设您已经具备创建自定义组件和包的一般知识,您可以在其中发布此属性编辑器,因为这本身就是一堂课,我不会介绍.这只需要在 Register
过程中放置一行代码,但我们稍后会介绍.
I am assuming that you already have a general knowledge of creating custom components and a package in which you can publish this property editor from, because that's a lesson in its own which I will not cover. This calls for just one line of code to be placed inside the Register
procedure, but we'll get to that later.
首先,您需要在 Design-Time
包中创建一个新表单,您的组件已在其中注册.将单元命名为 DateTimeProperty.pas
,并将表单命名为 DateTimeDialog
(从而使表单的类为 TDateTimeDialog
).放置您需要的任何控件,在本例中为 TMonthCalendar
、TDateTimePicker
(Kind
设置为 dtkTime
)和2 个 TBitBtn
控件,一个标有 OK
与 mrOK
的 ModalResult
,另一个标有 Cancel
带有 mrCancel
的 ModalResult
.
First, you need to create a new form in your Design-Time
package, where your components are registered. Name the unit DateTimeProperty.pas
, and name the form DateTimeDialog
(thus making the form's class TDateTimeDialog
). Place whatever controls you need, in this case a TMonthCalendar
, TDateTimePicker
(with Kind
set to dtkTime
), and 2 TBitBtn
controls, one labeled OK
with ModalResult
of mrOK
and the other labeled Cancel
with ModalResult
of mrCancel
.
你的单位应该是这样的:
Your unit should look something like this:
unit DateTimeProperty;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.ComCtrls, Vcl.StdCtrls, Vcl.Buttons;
type
TDateTimeDialog = class(TForm)
dtDate: TMonthCalendar;
dtTime: TDateTimePicker;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
private
public
end;
var
DateTimeDialog: TDateTimeDialog;
implementation
{$R *.dfm}
end.
这是表单背后的DFM
代码:
object DateTimeDialog: TDateTimeDialog
Left = 591
Top = 158
BorderIcons = [biSystemMenu]
BorderStyle = bsToolWindow
Caption = 'Pick Date/Time'
ClientHeight = 231
ClientWidth = 241
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
DesignSize = (
241
231)
PixelsPerInch = 96
TextHeight = 13
object dtDate: TMonthCalendar
Left = 8
Top = 31
Width = 225
Height = 166
Anchors = [akLeft, akRight, akBottom]
Date = 41261.901190613430000000
TabOrder = 1
end
object dtTime: TDateTimePicker
Left = 8
Top = 8
Width = 113
Height = 21
Date = 41261.000000000000000000
Time = 41261.000000000000000000
Kind = dtkTime
TabOrder = 2
end
object BitBtn1: TBitBtn
Left = 158
Top = 200
Width = 75
Height = 25
Caption = 'OK'
Default = True
ModalResult = 1
TabOrder = 0
end
object BitBtn2: TBitBtn
Left = 77
Top = 200
Width = 75
Height = 25
Caption = 'Cancel'
ModalResult = 2
TabOrder = 3
end
end
现在,将 DesignEditors
和 DesignIntf
添加到您的 uses
子句中.确保您在 Design-Time
包的 Requires
中声明了 DesignIDE
.这是发布任何属性编辑器所必需的.
Now, add DesignEditors
and DesignIntf
to your uses
clause. Make sure you have DesignIDE
declared in the Requires
of this Design-Time
package. This is required for publishing any property editors.
在表单中,使用属性 getter 和 setter 创建一个名为 DateTime
的类型为 TDateTime
的新公共属性.此属性将允许您轻松读取/写入选择实际代表的完整 TDateTime
值.所以你应该在你的表单中有这个:
In the form, create a new public property called DateTime
of type TDateTime
with a property getter and setter. This property will allow you to easily read/write the full TDateTime
value the selection actually represents. So you should have this in your form:
private
function GetDateTime: TDateTime;
procedure SetDateTime(const Value: TDateTime);
public
property DateTime: TDateTime read GetDateTime write SetDateTime;
....
function TDateTimeDialog.GetDateTime: TDateTime;
begin
Result:= Int(dtDate.Date) + Frac(dtTime.Time);
end;
procedure TDateTimeDialog.SetDateTime(const Value: TDateTime);
begin
dtDate.Date:= Value;
dtTime.DateTime:= Value;
end;
接下来我们需要添加实际的属性编辑器类.在 {$R *.dfm}
下创建这个类,它就在 implementation
下:
Next we need to add the actual property editor class. Create this class just beneath the {$R *.dfm}
which is just under implementation
:
type
TDateTimeEditor = class(TDateTimeProperty)
public
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
function GetValue: String; override;
procedure SetValue(const Value: String); override;
end;
procedure TDateTimeEditor.Edit;
var
F: TDateTimeDialog;
begin
//Initialize the property editor window
F:= TDateTimeDialog.Create(Application);
try
F.DateTime:= GetFloatValue;
if F.ShowModal = mrOK then begin
SetFloatValue(F.DateTime);
end;
finally
F.Free;
end;
end;
function TDateTimeEditor.GetAttributes: TPropertyAttributes;
begin
//Makes the small button show to the right of the property
Result := inherited GetAttributes + [paDialog];
end;
function TDateTimeEditor.GetValue: String;
begin
//Returns the string which should show in Object Inspector
Result:= FormatDateTime('m/d/yy h:nn:ss ampm', GetFloatValue);
end;
procedure TDateTimeEditor.SetValue(const Value: String);
begin
//Assigns the string typed in Object Inspector to the property
inherited;
end;
最后,我们需要添加一个Register
过程来执行这个新属性编辑器的实际注册:
Finally, we need to add a Register
procedure to perform the actual registration of this new property editor:
procedure Register;
begin
RegisterPropertyEditor(TypeInfo(TDateTime), nil, '', TDateTimeEditor);
end;
现在对 RegisterPropertyEditor
的调用有一个重要的部分需要理解.由于第二个和第三个参数是 nil
和一个空字符串,这意味着编辑器将应用于 TDateTime
的所有实例.查看此过程以获取有关使其特定于某些组件和属性实例的更多信息.
Now there's an important piece to understand in this call to RegisterPropertyEditor
. Since the 2nd and 3rd parameters are nil
and an empty string, this means the editor will apply to all instances of TDateTime
. Look into this procedure for more information about making it specific to certain components and property instances.
这是安装后的最终结果...
And here's the final result after installing...
为自定义属性编辑器贡献的一些很好的资源如下:
Some good resources for custom property editors which contributed are as follows:
- 如何制作自定义组件属性?
- http://delphi.about.com/library/bluc/text/uc092501d.htm
- http://www.sandownet.com/propedit.html
这篇关于如何为某种类型的所有实例实现我自己的自定义属性编辑器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!