Смесь бульдога с носорогомИсточник: 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). |