Алксандр Божко
В одном из предыдущих постов я упоминал о переводе 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).
Ссылки по теме