Смесь бульдога с носорогом

Источник: delphi2010
Алксандр Божко

В одном из предыдущих постов я упоминал о переводе Delphi проекта на DevExpress. Поскольку одной из основных причин такого решения была необходимость создания т.н. Ribbon -интерфейса, то в проекте пришлось менять все контролы. Сами понимаете, на фоне Ribbon-меню обычные серые кнопки, списки, радио-баттоны и чек-боксы смотрятся не очень... Очень быстро выяснилось, что переделать главное меню - не самое сложное. Компонент TdxBarConverter успешно решает эту задачу (требуется лишь легкая "доработка напильником"). Но если проект содержит несколько сотен контролов, которые активно используются в коде, то о трудоемкости их замены в ручную лучше и не говорить. К счастью существует несколько бесплатных расширений IDE, позволяющих автоматизировать этот процесс. Я пользуюсь, как мне кажется, лучшим из бесплатных решений - набором GExperts. Одной из его возможностей является автоматическая замена одного контрола на другой. При этом можно заменить не просто единичный элемент, но и все элементы на форме или в проекте. Конечно, заменять с помощью данного инструмента, такие сложные компоненты, как DBGrid не стоит. Все же у того же DBGridEh и cxGrid абсолютно разная структура. Но с DBComboBox'ами и прочими "простыми" контролами GExperts справляется не плохо. Если бы не одно "НО"... Учитывая то, что котнтролы DevExpress просто перенасыщены функциональностью, из создатели решили упростить жизнь своим клиентам (а возможно и себе). Ряд свойств большинства контролов был сгруппирован в отдельные классы. Так скажем, обратиться к списку значений TcxComboBox можно следующим образом:

cxComboBox.Proiperties.Items ...

в то время, как для VCL-евского TComboBox обращение будет выглядеть так:

ComboBox1.Items ...

Естественно, что мастер замены контролов не может развязать такие несовпадения и их приходится править вручную... Даже имея перед собой два монитора, я быстро пришел к выводу, что поэлементное сравнение каждой формы - занятие весьма утомительное. Решение же данной проблемы оказалось довольно простым.

unit cxATRComboBox;

interface

uses
  SysUtils, Classes, Controls, cxControls, cxContainer, cxEdit, cxTextEdit,
  cxMaskEdit, cxDropDownEdit;

type

  TcxATRComboBox = class(TcxComboBox)
  private
    FOnChange: TNotifyEvent;
    FOnDropDown: TNotifyEvent;

    function GetItems: Tstrings;
    procedure SetItems(const Value: Tstrings);
    function GetOnChange: TNotifyEvent;
    procedure SetOnChange(const Value: TNotifyEvent);
    function GetDropDown: TNotifyEvent;
    procedure SetDropDown(const Value: TNotifyEvent);
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
   constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
     property Items: Tstrings read GetItems write SetItems;
     property OnChange: TNotifyEvent read GetOnChange write SetOnChange;
     property OnDropDown: TNotifyEvent read GetDropDown write SetDropDown;

  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Dev Express My Own', [TcxATRComboBox]);
end;

{ TcxATRComboBox }

constructor TcxATRComboBox.Create(AOwner: TComponent);
begin
  inherited;

end;

function TcxATRComboBox.GetDropDown: TNotifyEvent;
begin
 Result:= FOnDropDown;
end;

function TcxATRComboBox.GetItems: Tstrings;
begin
  Result:= self.Properties.Items;
end;

function TcxATRComboBox.GetOnChange: TNotifyEvent;
begin
Result:= FOnChange;
end;

procedure TcxATRComboBox.SetDropDown(const Value: TNotifyEvent);
begin
 self.Properties.OnPopup:=Value;
 FOnDropDown:= Value;
end;

procedure TcxATRComboBox.SetItems(const Value: Tstrings);
begin

  if Assigned(self.Properties.Items) then
    self.Properties.Items.Assign(Value)
  else
    self.Properties.Items := Value;

end;

procedure TcxATRComboBox.SetOnChange(const Value: TNotifyEvent);
begin
 self.Properties.OnChange:=Value;
 FOnChange:= Value;
end;

end.

Как видно из кода, мы просто создаем наследника для каждого из "неприятных" контролов. В этих наследниках мы попросту вводим "недостающие" свойства и считывая и записывая их значения ссылаемся на аналогичные имеющиеся в классе-родителе. Так у нас появляется свойство Items, хотя фактически работая с ним, мы работаем со свойством Properties.Items. И мастер замены компонентов доволен таким соответствием взаимозаменяемых классов и компилятор не ругается... Классический пример того как "лучше день потерять, но за пять минут долететь" (c).


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=21875