Создание компонентов для KOL и MCK - Часть 4 - Создание визуальных MCK объектов
Ведущий раздела KOL и MCK: Анатолий aka XVeL
Автор: Жаров Дмитрий aka Gandalf
WEB-сайт: http://kol.mastak.ru
Полную версию библиотеки KOL и MCK можно скачать здесь
Создание визуальных MCK объектов: Не опять, а снова
Вообще-то учить вас тут нечему, различий тут еще меньше чем в KOL
части, но кое-что еще есть. Визуальные компоненты наследуются от
TKOLControl - он специально для этого создан. Мы добавили свое событие,
как добавить код, и какой? Ну, это не сложно, потупим так (часть кода
вырезана):
uses
Windows, Controls, Classes, mirror, KOL, Graphics, MCKCtrls, KOLMHTrackBar;
type
TKOLMHTrackBar = class(TKOLControl)
private
…
FOnScroll: TOnScroll;
procedure SetOnScroll(const Value: TOnScroll);
…
public
property OnScroll: TOnScroll read FOnScroll write SetOnScroll;
…
end;
Вот и все, будет жить. Да обратите внимание на uses - я его не просто
так привел, TOnScroll есть в разных модулях, нам нужен тот, который в
KOLMHTrackBar, поэтому порядок следования важен! Чтобы не полагаться на
порядок лучше писать KOLMHTrackBar. TOnScroll. Но это событие уже было
определено, и мы его переопределили, если создано новое, то надо
переопределить процедуру AssignEvents - она занимается регистрацией
событий. Делается это так:
protected
procedure AssignEvents(SL: TStringList; const AName: string); override;
…
procedure TKOLMHTrackBar.AssignEvents(SL: TStringList; const AName: string);
begin
inherited;
DoAssignEvents( SL, AName, [ 'OnMyEvent'], [ @OnMyEvent] );
end;
Не много труда! Да вот важный момент, если мы попытаемся сейчас
применить компонент, нас обругает компилятор, мол, несоответствие типов
(Incompatible types: 'TControl' and 'TMHTrackBar' - если дословно). Чтобы
сохранить паритет, надо их привести к одному знаменателю, я предлагаю
сделать так - переопределить конструкцию создания:
protected
procedure SetupConstruct( SL: TStringList; const AName, AParent, Prefix: string ); override;
…
procedure TKOLMHTrackBar.SetupConstruct(SL: TStringList; const AName, AParent, Prefix: string);
var S: String;
begin
S := GenerateTransparentInits;
SL.Add( Prefix + AName + ' := PMHTrackbar( New' + TypeName + '( ' +
SetupParams( AName, AParent ) + ' )' + S + ');' );
end;
Благодаря этому коду, у нас теперь будет генерироваться, нет, не New,…
а PMHTrackBar(New…. (SetupParams - узнаете)), элементарно. Мы изменили
конструкцию генерации! GenerateTransparentInits - нужен для последующей
совместимости с KOL и MCK, он пока ничего не делает, но когда будет
реализована прозрачность он себя покажет. Для рассмотрения еще одного
момента добавим в наш компонент Buddyes - такие окошки, которые
располагаются рядом с TrackBar'ом, в качестве их можно назначить любой
компонент. В KOL часть такой код:
private
function GetHandle(const Index: Integer): HWnd;
procedure SetHandle(const Index: Integer; const Value: HWnd);
…
public
…
property BuddyRightBottom: HWnd index 0 read GetHandle write SetHandle;
property BuddyLeftTop: HWnd index 1 read GetHandle write SetHandle;
…
function TMHTrackbar.GetHandle(const Index: Integer): HWnd;
const
Mes: array [0..1] of DWord = (TBM_GETBUDDY, TBM_GETBUDDY);
begin
Result := Perform(Mes[Index], Index, 0);
end;
procedure TMHTrackbar.SetHandle(const Index: Integer; const Value: HWnd);
const
Mes: array [0..1] of DWord = (TBM_SETBUDDY, TBM_SETBUDDY);
begin
Perform(Mes[Index], Index , Value);
end;
А в MCK часть:
private
…
FBuddyLeftTop: TKOLControl;
FBuddyRightBottom: TKOLControl;
procedure SetBuddyLeftTop(const Value: TKOLControl);
procedure SetBuddyRightBottom(const Value: TKOLControl);
published
…
property BuddyLeftTop: TKOLControl read FBuddyLeftTop write SetBuddyLeftTop;
property BuddyRightBottom: TKOLControl read FBuddyRightBottom write SetBuddyRightBottom;
…
procedure TKOLMHTrackBar.SetBuddyLeftTop(const Value: TKOLControl);
begin
FBuddyLeftTop := Value;
Change;
end;
procedure TKOLMHTrackBar.SetBuddyRightBottom(const Value: TKOLControl);
begin
FBuddyRightBottom := Value;
Change;
end;
Теперь мы можем выбирать компонент из формы и назначать в качестве
Buddy, но не торопитесь добавлять код в SetupFirst:
if FBuddyLeftTop <> nil then
SL.Add(Prefix + AName + '.BuddyLeftTop:=Result.' + FBuddyLeftTop.Name + '.GetWindowHandle;');
if FBuddyRightBottom <> nil then
SL.Add(Prefix + AName + '.BuddyRightBottom:=Result.' + FBuddyRightBottom.Name +
'.GetWindowHandle;');
Это не будет работать! Фокус в том мы пытаемся, присвоит Handle
объектов до того, когда они созданы, это невозможно. Что же делать? Выход
есть! Надо использовать SetupLast. Он займется обеспечением того, чтобы
сначала Buddyes были созданы, а потом уже было присвоение кода.
Механически это выполняется при помощи изменения положения строк кода.
Т.е. сначала идет код создания Buddyes, а потом присвоение Handle.
Поступаем следующим образом:
protected
procedure SetupLast(SL: TStringList; const AName, AParent, Prefix: String); override;
…
procedure TKOLMHTrackBar.SetupLast(SL: TStringList; const AName, AParent, Prefix: String);
begin
inherited;
if FBuddyLeftTop <> nil then
SL.Add(Prefix + AName + '.BuddyLeftTop:=Result.' + FBuddyLeftTop.Name + '.GetWindowHandle;');
if FBuddyRightBottom <> nil then
SL.Add(Prefix + AName + '.BuddyRightBottom:=Result.' +
FBuddyRightBottom.Name + '.GetWindowHandle;');
if FToolTip <> nil then
SL.Add(Prefix + AName + '.ToolTip:=Result.' + FToolTip.Name + '.GetWindowHandle;');
end;
Теперь последние штрихи. Вас не
раздражают в ObjectInspector'е лишние свойства? Они достались нам в
наследство от TKOLControl. Уберем их, для этого сделаем фиктивную
переменную, и переопределим свойства только, на чтение - такие свойства
ObjectInspector прячет:
private
…
// Фиктивное свойство
FNotAvailable: Boolean;
…
public
…
property Caption: Boolean read FNotAvailable;
property Color: Boolean read FNotAvailable;
property Font: Boolean read FNotAvailable;
end;
Их больше нет! Теперь запустим компонент, чего не хватает, что
режет глаз? Отрисовка, вместо красивого ползунка - прямоугольник и гордым
именем. Я не буду давать уроков рисования - рисовать компоненты будете вы,
я подскажу, как это реализовать. Сначала переопределим Paint:
protected
procedure Paint; override;
Но этого мало, надо сказать MKC, что вы можете отрисовать
компонент, но это еще проще:
protected
function WYSIWIGPaintImplemented: Boolean; override;
function TKOLEditBox.WYSIWIGPaintImplemented: Boolean;
begin
Result := TRUE;
end;
Я помню еще те времена, когда у MCK не было отрисовки совсем, это
(меня) страшно злило, и я начал поиски - идея повторять отрисовку
MicroSoft меня не вдохновляло (повторять - всегда сложно, а ведь нужно
именно повторить). Но никуда не денешься, пришлось рисовать, я, собрав
волю в кулак, сделал отрисовку Label, Edit. Пример оказался заразительным
сейчас большинства компонентов есть отрисовка. Бог в помощь! Ну вот,
пожалуй, и все, действительно все.
Заключение: Пожалуй, не все… Да, я не претендую на полноту
изложения. Я сказал не все! Времени не хватило, сил. Набирая эти строки, я
обдумываю еще пару глав, кое-какие дополнения, коррективы. Есть
компоненты, которым не нужна KOL часть. Есть вариант наследования
визуальных компонентов от TObj, еще много чего есть. Есть еще и
специфические моменты, с которыми, вы не встретитесь, а если встретитесь,
то моя помощь уже вам будет не нужна. Наверно после прочтения этой статьи
остались те, кому она не понравилась, те кто ее не понял, те кто поняли,
что это не для них. Но я верю, что были и те, кто до прочтения не знал,
как создавать компоненты под KOL и MCK , а после прочтения стали их
делать. Эту статью я писал для них. И если они есть, я работал не
напрасно. Прошу вас KOL и MCK - это точно не VCL. Не городите лишних
компонентов, сделайте основные компоненты. Не дублируйте имеющиеся -
развивайте их. Возможно, эту статью должен был написать Кладов, но ее
написал я…
|