Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Создание компонентов для 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);
  …
publicproperty 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);
publishedproperty 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;
  …
publicproperty 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. Не городите лишних компонентов, сделайте основные компоненты. Не дублируйте имеющиеся - развивайте их. Возможно, эту статью должен был написать Кладов, но ее написал я…

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay