Как я могу реализовать свой собственный редактор свойств для всех экземпляров определенного типа?

Я следовал нескольким учебникам по созданию диалогового окна редактора пользовательских свойств, но в нем так много всего, что я не мог заставить его работать правильно. То, что я пытаюсь сделать, - это пользовательская форма со средством выбора даты (календарь), средством выбора времени и кнопками OK и Отмена. С формой нет проблем, но как мне реализовать это, чтобы я мог опубликовать свойство в любом компоненте определенного типа с кнопкой для запуска редактора свойств?

Я хотел бы полностью переопределить TDateTime введите и поместите мой пользовательский редактор на свое место, так что везде TDateTime опубликован и виден в Инспекторе объектов, я могу использовать этот редактор для изменения даты и времени вместе в одном окне.

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

1 ответ

Решение

Я не хотел задавать этот вопрос здесь и ожидать, что кто-нибудь ответит на него за меня, поэтому я провел исследование сам, чтобы решить свои проблемы, и я хотел бы поделиться уникальным опытом, связанным с этим мини-проектом, так как я уверен, что другие разочарован тем же.

Существует множество различных возможностей с настраиваемыми редакторами свойств, диалогами и редакторами компонентов. Это, в частности, потребовало бы TDateTimeProperty потомок. Это позволит вам иметь возможность редактировать значение свойства непосредственно в Инспекторе объектов как обычный текст (String), сохраняя при этом форматирование DateTime.

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

Во-первых, вам нужно создать новую форму в вашем Design-Time пакет, где ваши компоненты зарегистрированы. Назовите единицу DateTimeProperty.pasи назовите форму DateTimeDialog (таким образом, делая класс формы TDateTimeDialog). Разместите все необходимые элементы управления, в этом случае TMonthCalendar, TDateTimePickerKind установлен в dtkTime) и 2 TBitBtn элементы управления, один с надписью OK с ModalResult из mrOK а другой помечен Cancel с ModalResult из mrCancel,

Ваше устройство должно выглядеть примерно так:

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 пункт. Убедитесь, что у вас есть DesignIDE объявлено в Requires этого Design-Time пакет. Это необходимо для публикации любых редакторов свойств.

В форме создайте новую публичную собственность с именем DateTime типа TDateTime с свойства геттер и сеттер. Это свойство позволит вам легко читать / писать полный TDateTime значение, которое фактически представляет выбор. Так что вы должны иметь это в вашей форме:

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:

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 Порядок выполнения фактической регистрации этого нового редактора недвижимости:

procedure Register;
begin
  RegisterPropertyEditor(TypeInfo(TDateTime), nil, '', TDateTimeEditor);
end;

Теперь есть важный момент, который нужно понять в этом призыве RegisterPropertyEditor, Поскольку 2-й и 3-й параметры nil и пустая строка, это означает, что редактор будет применяться ко всем экземплярам TDateTime, Просмотрите эту процедуру для получения дополнительной информации о том, как сделать ее специфичной для определенных компонентов и экземпляров свойств.

И вот окончательный результат после установки...

Образец окончательного редактора свойств

Вот некоторые полезные ресурсы для редакторов пользовательских свойств:

  1. как сделать собственное свойство компонента?
  2. http://delphi.about.com/library/bluc/text/uc092501d.htm
  3. http://www.sandownet.com/propedit.html
Другие вопросы по тегам