Часто задаваемые Вопросы и Ответы на них (ЧаВО)
 
Что такое KOL? Что такое MCK?
    KOL - это библиотека объектных типов для программирования в среде Delphi. Основная цель KOL - уменьшение размера конечной программы (Win32, GUI) в 5-10 раз по сравнению с тем, что дает VCL. Поддерживаются все 32-разрядные версии Delphi, начиная с Delphi2 и заканчивая Delphi7.
   MCK - это набор зеркальных компонент, позволяющих разрабатывать проект на основе библиотеки KOL визуально. Компоненты MCK устанавливаются на палитру компонентов, работа с ними происходит так же, как это обычно делается в Delphi при визуальной разработке. В откомпилированном проекте визуальные компоненты замещаются своими невизуальными двойниками из KOL. Использование MCK сокращает размер исполнимой программы так же, как и при использовании KOL невизуально. Преимущество - визуальная разработка. Недостаток - некоторая зависимость от версии Delphi (проект, выполненный в более новой версии Delphi, не всегда удается открыть в более старой).
 
Зависит ли размер программы, сделанной с помощью KOL, от версии Delphi?
В очень малой степени. Разница между версиями Delphi3 и Delphi5 может колебаться (обычно) в пределах 1Кбайта, причем в любую сторону. Однако, замена system.dcu предлагается пока только для Delphi4-Delphi7, а с этой заменой программа может быть еще на 9-10К меньше. Так что выбирайте сами.
 
Возможно ли использовать одновременно KOL и VCL или, установив KOL, я не смогу воспользоваться VCL, не переустановив DELPHI?
Установка KOL заключается в его сохранении в выбранную вами директорию. Далее модуль KOL.pas и другие необходимые модули используются обычным для языка Pascal способом - добавлением ссылки на них в списке используемых модулей uses. Это никак не влияет на проекты VCL. Аналогично, установка MCK заключается в установке набора зеркальных компонентов на палитру Delphi. Прочие компоненты в палитре не затрагиваются (если их имя не совпадает с именами компонентов MCK. Обычно это так, т.к. все компоненты MCK должны именоваться TKOLxxxxx).
 
Библиотека KOL развивается, добавляются новые события, свойства, методы. Не опасаетесь ли Вы, что ваша библиотека раздуется до таких же размеров, как VCL? (И в чем тогда смысл изобретать велосипед...)
Нисколько! Благодаря своей продуманной организации, KOL позволяет компилятору Delphi использовать так называемый smart-linking (дословно: "остроумное связывание"). Возьмем, к примеру, одно из дополнений: событие OnDropFiles (добавлено 1 мая 2001, v0.71). Если оно не используется и не назначено, код программы не увеличивается НИ НА ОДИН БАЙТ. И только в случае, когда такое событие использовано в конечной программе, из библиотеки будет добавлен код двух процедур: метода SetOnDropFiles и процедуры WndProcDropFiles. Все дело в том, что на процедуру WndProcDropTarget имеется ссылка только из метода SetDropTarget, на который ссылка появляется только в случае явного присваивания значения событию OnDropTarget. И так устроена практически вся библиотека. (Так должна была бы быть построена VCL, но поскольку она устроена НЕ ТАК, то она и не может конкурировать с KOL в плане экономии кода, подключаемого к исполнимой программе).
 
Я устанавливаю дополнительный MCK-компонент XXXXX в Delphi6 (7). Создаю package, добавляю модуль XXXXX.pas, пытаюсь package установить, а в ответ получаю сообщение, что не найден модуль Proxies.dcu. И где я только такой модуль не искал, не могу найти. Что делать?
Это обычная ситуация для Delphi6 (7). Добавьте в части использования ссылку на DesignIDE.dcp. Не забудьте также указать в опциях пакета 'Design time only' и 'Rebuild as needed' - это касается в том числе любой другой версии Delphi (начиная с D3).
 
У меня в MirrorKOLPackageD6 (MirrorKOLPackageD7) уже имеется ссылка на designide.dcp, но проект не компилируется: Delphi требует файл proxies.pas (dsgnintf.pas). Где взять такой файл?
Один из следующих вариантов:
1. Ваш проект не является проектом MCK. Пожалуйста, прочитайте внимательно инструкцию - "III. НАЧАЛО НОВОГО ЗЕРКАЛЬНОГО ПРОЕКТА".
2. Либо после добавления на форму очередного компонента в uses автоматически добавилась ссылка на модуль VCL (возможно, на модуль mckobjs.pas, сам входящий в MCK), и попала при этом за пределы скобок $IFNDEF KOL_MCK...$ENDIF. Надо в этом случае вручную переместить ссылку на такой модуль внутрь этих "скобок".
3. Или, возможно, пропали какие-то файлы, содержащие важную информацию об опциях проекта. Правильные опции можно посмотреть, создав новый проект в соответствии с инструкцией, и открыв Projects|Options|Directories\Conditions. Строка Conditional defines должна содержать символ KOL_MCK, и в строке Unit aliases, обычное значение "Classes=;mirror=". Установите такие же опции для вашего проекта.
 
Я использую замену sys*.dcu, но не могу использовать Write и другие подобные функции для работы с текстовыми файлами. Как мне заставить их работать?
1. Прочитать readme.txt :)
2. Вызвать процедуру UseInputOutput (один раз, например в dpr-файле).
   
Я не использую замену sys*.dcu, но не могу использовать try-except. Что нужно сделать, чтобы обработка исключительных ситуации работала правильно?
Использовать в проекте модуль err.pas из пакета kol_err.zip.
Примечание: для правильной работы try-finally этот модуль не требуется.
   
Как реализовать кнопку по умолчанию, срабатывающую на нажатию клавиши Enter или Escape?
1. Теперь такая кнопка может быть назначена визуально в MCK или свойствами DefaultBtn, CancelBtn.
2. Можно по-прежнему использовать событие Applet.OnMessage.
   
У меня установлен шрифт 125%. В VCL есть у формы свойство Scaled. Достаточно поставить его в False, и надписи на кнопках, метках и т.д. помещаются вне зависимости от разрешения экрана. Как сделать то же самое в KOL?
В том-то и дело, что ничего делать не надо. Кроме того, что прекратить использовать шрифт по умолчанию. Для этого достаточно обратиться к свойству Font формы сразу после ее создания (в результате происходит создание объекта TGraphicTool, реализующего шрифт, который в последующем устанавливается текущим для окна). Или можно обратиться к свойству Font окна приложения, родительского для всех форм. Например, так: MyForm.Font;
Или, можно сразу же и изменить какое-либо свойство шрифта. Например, установить новый стиль, цвет, размер. Учтите, что по умолчанию шрифт получает значения, прописанные в глобальных переменных DefFontHeight (20 пикселов), DefFontName ('MS Sans Serif') и т.д. В то же время, любые дочерние визуальные контролы в момент создания унаследуют шрифт от родительского окна (если шрифт установлен в родительском окне).
Кроме того, в настоящее время поддерживается свойство AutoSize для таких визуальных объектов, как метка, кнопка, односточное поле ввода и т.п. В сочетании с возможностью задавать выравнивание (Align) для любых визуальных объектов это дает возможность обеспечить правильное отображение форм независимо от текущих пользовательских установок.
   
Когда используется переменная Applet, анимация при минимизации происходит не с позиции главной формы, а от верхнего левого угла экрана. Как это поправить?
Воспользоваться методом (в MCK - свойством) MinimizeNormalAnimated.
   
Как сделать DLL, содержащую форму, изготовленную в KOL, и правильно вызвать ее?
Создать форму как обычно и оттестировать ее в обычном приложении, без DLL (форму можно создать визуально, используя MCK). Затем, приготовить проект DLL, содержащий экспортируемую функцию:

   function ExecuteKOLform( < параметры > ): Integer;
   stdcall;
   var MyKOLForm: PControl;
   begin
     Applet := NewApplet( '' );
     MyKOLForm := NewForm( Applet, 'DllKolForm' );
     ... // здесь создать прочие элементы формы,
         // проинициализировать, ...
     MyKOLForm.ShowModal;
     ... // здесь можно прочитать состояние некоторых
         // визуальных элементов, поскольку они все еще
         // существуют
     Applet.Free;
   end;
См. также соответствующий Demo-проект.
   
Как правильно оформить вызов модальной формы?
Всего имеется два варианта. Более простой, когда модальная форма создается непосредственно перед показом и разрушается сразу после того, как модальный диалог завершен - проще. И не требует использования отдельного объекта Applet (в MCK - не обязательно использовать компонент TKOLApplet на главной форме).

// показ модального диалога с его созданием
// непосредственно перед началом диалога и
// с разрушением - после:
procedure TForm1.Button1Click(Sender: PObj);
begin
  NewForm2( Form2, Applet );
  // добавьте здесь свой код для инициализации
  // контролов формы Form2
  Form2.Form.ShowModal;
  // добавьте здесь свой код для чтения
  // состояний контролов формы Form2
  Form2.Form.Free; // нельзя использовать Close !
  //ShowMessage( 'End of TForm1.Button1Click' );
end;

// Для такого варианта достаточно определить
// вот такой обработчик какой-либо кнопки
// (но и он не требуется - достаточно закрыть
// форму обычным образом, нажимая "крестик"
// в заголовке окна, в этом случае значение
// ModalResult = -1 по завершении).
procedure TForm2.Button1Click(Sender: PObj);
begin
  Form.ModalResult := 1; // любое значение <> 0
end;

Чуть посложнее случай, когда форма существует (и обычно невидима), ее нужно модально показать, но не уничтожать по завершении диалога, а просто скрыть. В этом случае использование отдельного объекта Applet обязательно, главная форма не может выполнять его роль. Для MCK-проекта это означает, что на главную форму надо бросить компонент TKOLApplet.

// Показ диалога модально:
procedure TForm1.Button1Click(Sender: PObj);
begin
  Form2.Form.ShowModal;
  Form2.Form.Hide;
end;

// Завершение диалога по кнопке:
procedure TForm2.Button1Click(Sender: PObj);
begin
  Form.ModalResult := 1;
end;

// Обязательно надо определить событие OnClose
// и предотвратить в нем закрытие формы Form2:
procedure TForm2.KOLForm1Close(Sender: PObj;
            var Accept: Boolean);
begin
  Accept := FALSE;        // предотвращаем закрытие
  Form.ModalResult := -1; // любое значение <> 0
end;
Заметьте, что в обоих случаях за финальные действия (Close или Hide) отвечает код, инициирующий диалог, а не код, принадлежащий самой модальной форме.
   
Возможно ли разрабатывать DLL, содержащую формы KOL визуально, используя MCK?
Конечно. Создайте проект MCK как обычно, и затем измените слово program в dpr-file на library. Сделайте формы не автоматически создаваемыми, и добавьте экспортируемые функции подобно тому, как это показано в ответе на предыдущий вопрос.
Чтобы предотвратить срабатывание Run( Applet ), измените файл <ваш_проект>_1.inc. Например, допишите туда:
  Exit;
   
Я хочу перемещать кнопку (или другой визуальный элемент) с помощью мыши. Как это сделать?
Следующий код работает для всех типов визуальных объектов, включая кнопки:
procedure TForm1.BitBtn1MouseMove(Sender: PControl;
            var Mouse: TMouseEventData);
begin
  if FBtn1Down then
    BitBtn1.DragStartEx;
end;

procedure TForm1.BitBtn1MouseDown(Sender: PControl;
            var Mouse: TMouseEventData);
begin
  if Mouse.Button = mbLeft then
    FBtn1Down := TRUE;
end;

procedure TForm1.BitBtn1MouseUp(Sender: PControl;
            var Mouse: TMouseEventData);
begin
  FBtn1Down := FALSE;
  BitBtn1.DragStopEx;
end;
( переменная FBtn1Down: Boolean; должна быть объявлена в объекте TForm1 ).

И, для большинства типов визуальных объектов достаточен следующий код:
procedure TForm1.Panel1MouseDown(Sender: PControl;
var Mouse: TMouseEventData);
begin
  Panel1.DragStart;
end;
Но этот вариант не работает для кнопок, и обеспечивает перетаскивание только при нажатой левой клавиши мыши.
   
Как рисовать прямо на рабочем столе, используя объект канвы (PCanvas) ?
procedure TForm1.Toolbar1TB1Click
      (Sender: PControl; BtnID: Integer);
var C: PCanvas;
    D: HDC;
begin
  D := GetDC( 0 );
  C := NewCanvas( D );

  C.LineTo( 400, 400 ); // используем методы
                        // и свойства TCanvas

  C.Free;
  ReleaseDC( 0, D );
end;
   
У меня на форме два (или больше) тулбара, и проект не компилируется: сообщает, что имя TB1 дублируется.
Следует назначить кнопкам тулбара уникальные имена. Например, TBOpen, TBClose, и т.п. В этом случае и обращаться к свойствам кнопок удобно используя эти имена вместо голых индексов, например: Toolbar1.TBButtonVisible[ TBSave ]. Более того, теперь не надо исправлять исходный код программы при изменении состава кнопок на тулбарах.
Если вы не желаете менять имена кнопок тулбара на уникальные, просто выключите свойство GenerateButtonNames. То же самое имеет место для колонок list view, и пунктов меню.
      
Как правильно назначить в качестве обработчика события (например, OnMessage) процедуру, не являющуюся методом объекта? MainForm.OnMessage := TOnMessage(MakeMethod(nil,@OnHotKey)); где процедура OnHotKey описана как: function OnHotKey( var Msg: TMsg; var Rslt: Integer ): Boolean; вызывает ошибку во время исполнения.
Процедура-метод (функция-метод) объекта (класса) отличается от регулярной процедуры (функции) только наличием скрытого первого параметра, представляющего собой переменную Self объекта. Практически все события описаны как procedure(...) of object или function( ... ):... of object, т.е. обработчиком должен быть метод объекта (класса). Если требуется использовать регулярную процедуру или функцию, недостающий параметр должен быть описан явно:
function OnHotKey( Dummy_Self: PObj; var Msg: TMsg; var Rslt: Integer ): Boolean;
В этом случае на месте первого параметра правильно передается тот объект, который был задан первым параметром функции MakeMethod (в выше приведенном коде это nil). Если же этот параметр пропущен, то nil передается на месте параметра Msg, из-за чего и происходит ошибка во время исполнения.
  
Отладчик неверно показывает значения переменным в окне Watch. Как с этим бороться?
Проблема связана видимо с тем, что Code Insight считает, что имеет дело с классом, а не с объектом. Варианты борьбы:
1. Смотреть не свойство, а соответствующее ему поле: MyList.FCount вместо MyList.Count.
2. Использовать (хотя бы во время отладки) KOL с классами, см. KOL2FPC, теперь GlueCut.
  

Copyright (C) 1999-2006 by Vladimir Kladov