Создание компонентов для KOL и MCK - Часть 3 - Создание визуального KOL компонентаDelphi , Технологии , KOL и MCKСоздание компонентов для KOL и MCK - Часть 3 - Создание визуального KOL компонентаВедущий раздела KOL и MCK: Анатолий aka XVeL Полную версию библиотеки KOL и MCK можно скачать здесь Создание визуального KOL компонента: Сфера вид сбоку На самом деле создание визуальных компонентов под KOL и MCK не сильно отличается от создания не визуальных, но некоторые различия все же есть, они следует из разницы между визуальными и не визуальными компонентами вообще: unit KOLMHTrackBar; interface uses windows, messages, KOL; type PMHTrackBar =^TMHTrackBar; TKOLMHTrackBar = PMHTrackBar; TMHTrackBar = object(TControl) private function GetOnScroll: TOnScroll; procedure SetOnScroll(const Value: TOnScroll); function GetFrequency: DWord; procedure SetFrequency(const Value: DWord); procedure SetOrientation(const Value: TTrackBarOrientation); function GetOrientation: TTrackBarOrientation; public procedure Recreate; procedure ClearSel; property Orientation: TTrackBarOrientation read GetOrientation write SetOrientation; property Frequency: DWord read GetFrequency write SetFrequency; property Position: DWord index 2 read GetVal write SetVal; property OnScroll: TOnScroll read GetOnScroll write SetOnScroll; end; const TRACKBAR_CLASS = 'msctls_trackbar32'; TBS_AUTOTICKS = $0001; TBS_VERT = $0002; TBS_HORZ = $0000; TBS_TOP = $0004; TBS_BOTTOM = $0000; TBS_LEFT = $0004; TBS_RIGHT = $0000; TBS_BOTH = $0008; TBS_NOTICKS = $0010; TBS_ENABLESELRANGE = $0020; TBS_FIXEDLENGTH = $0040; TBS_NOTHUMB = $0080; TBS_TOOLTIPS = $0100; TBM_GETPOS = WM_USER; TBM_GETRANGEMIN = WM_USER + 1; TBM_GETRANGEMAX = WM_USER + 2; TBM_GETTIC = WM_USER + 3; TBM_SETTIC = WM_USER + 4; TBM_SETPOS = WM_USER + 5; TBM_SETRANGE = WM_USER + 6; TBM_SETRANGEMIN = WM_USER + 7; TBM_SETRANGEMAX = WM_USER + 8; TBM_CLEARTICS = WM_USER + 9; TBM_SETSEL = WM_USER + 10; TBM_SETSELSTART = WM_USER + 11; TBM_SETSELEND = WM_USER + 12; TBM_GETPTICS = WM_USER + 14; TBM_GETTICPOS = WM_USER + 15; TBM_GETNUMTICS = WM_USER + 16; TBM_GETSELSTART = WM_USER + 17; TBM_GETSELEND = WM_USER + 18; TBM_CLEARSEL = WM_USER + 19; TBM_SETTICFREQ = WM_USER + 20; TBM_SETPAGESIZE = WM_USER + 21; TBM_GETPAGESIZE = WM_USER + 22; TBM_SETLINESIZE = WM_USER + 23; TBM_GETLINESIZE = WM_USER + 24; TBM_GETTHUMBRECT = WM_USER + 25; TBM_GETCHANNELRECT = WM_USER + 26; TBM_SETTHUMBLENGTH = WM_USER + 27; TBM_GETTHUMBLENGTH = WM_USER + 28; TBM_SETTOOLTIPS = WM_USER + 29; TBM_GETTOOLTIPS = WM_USER + 30; TBM_SETTIPSIDE = WM_USER + 31; TBTS_TOP = 0; TBTS_LEFT = 1; TBTS_BOTTOM = 2; TBTS_RIGHT = 3; TBM_SETBUDDY = WM_USER + 32; TBM_GETBUDDY = WM_USER + 33; TBM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT; TBM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT; TB_LINEUP = 0; TB_LINEDOWN = 1; TB_PAGEUP = 2; TB_PAGEDOWN = 3; TB_THUMBPOSITION = 4; TB_THUMBTRACK = 5; TB_TOP = 6; TB_BOTTOM = 7; TB_ENDTRACK = 8; TBCD_TICS = $0001; TBCD_THUMB = $0002; TBCD_CHANNEL = $0003; Visible2Style: array [Boolean] of DWord = ($0, WS_VISIBLE); Orientation2Style: array [TTrackBarOrientation] of DWord = (TBS_HORZ, TBS_VERT); function NewMHTrackBar(AParent: PControl; Visible: Boolean; Orientation: TTrackBarOrientation; OnScroll: TOnScroll): PMHTrackBar; implementation type PTrackbarData = ^TTrackbarData; TTrackbarData = packed record FOnScroll: TOnScroll; FOrientation: TTrackBarOrientation; FFrequency: DWord; end; function WndProcTrackbarParent( Sender: PControl; var Msg: TMsg; var Rslt: Integer ): Boolean; var D: PTrackbarData; Trackbar: PMHTrackbar; begin Result := FALSE; if (Msg.message = WM_HSCROLL) or (Msg.message = WM_VSCROLL) then if (Msg.lParam <> 0) then begin Trackbar := Pointer( GetProp( Msg.lParam, ID_SELF ) ); if Trackbar <> nil then begin D := Trackbar.CustomData; if Assigned( D.FOnScroll ) then D.FOnScroll( Trackbar, Msg.wParam ); end; end; end; function NewMHTrackBar(AParent: PControl; Visible: Boolean; Orientation: TTrackBarOrientation; OnScroll: TOnScroll): PMHTrackBar; var D: PTrackbarData; begin DoInitCommonControls( ICC_BAR_CLASSES ); Result := PMHTrackbar(_NewCommonControl(AParent, TRACKBAR_CLASS, WS_CHILD or Visible2Style[Visible] or TBS_FIXEDLENGTH or TBS_ENABLESELRANGE or Orientation2Style[Orientation], False, 0)); GetMem(D, Sizeof(D^)); Result.CustomData := D; D.FOnScroll := OnScroll; AParent.AttachProc(WndProcTrackbarParent); end; procedure TMHTrackBar.Recreate; begin end; function TMHTrackBar.GetFrequency: DWord; var D: PTrackbarData; begin D := CustomData; Result := D.FFrequency; end; procedure TMHTrackBar.SetFrequency(const Value: DWord); var D: PTrackbarData; begin D := CustomData; D.FFrequency := Value; Perform(TBM_SETTICFREQ, Value, 1); end; function TMHTrackBar.GetOrientation: TTrackBarOrientation; begin Result := PTrackbarData(CustomData)^.FOrientation; end; procedure TMHTrackBar.SetOrientation(const Value: TTrackBarOrientation); begin PTrackbarData(CustomData)^.FOrientation := Value; Recreate; end; function TMHTrackbar.GetOnScroll: TOnScroll; var D: PTrackbarData; begin D := CustomData; Result := D.FOnScroll; end; procedure TMHTrackbar.SetOnScroll(const Value: TOnScroll); var D: PTrackbarData; begin D := CustomData; D.FOnScroll := Value; end; procedure TMHTrackbar.ClearSel; begin Perform(TBM_CLEARSEL, 1, 0); end; function TMHTrackbar.GetPosition: DWord; begin Result := Perform(TBM_GETPOS, 0, 0); end; procedure TMHTrackbar.SetPosition(const Value: DWord); begin Perform(TBM_SETPOS, 1, Value); end; end. Исходный код приведен не полностью, поскольку он довольно велик, из него были извлечены фрагменты, не содержащие информацию обучающего характера, если вы все же хотите увидеть весь код, вы можете найти их в Интернете или написать мне. function NewMHTrackBar(AParent: PControl; Visible: Boolean; Orientation: TTrackBarOrientation; OnScroll: TOnScroll): PMHTrackBar; var D: PTrackbarData; begin DoInitCommonControls( ICC_BAR_CLASSES ); Result := PMHTrackbar(_NewCommonControl(AParent, TRACKBAR_CLASS, WS_CHILD or Visible2Style[Visible] or TBS_FIXEDLENGTH or TBS_ENABLESELRANGE or Orientation2Style[Orientation], False, 0)); GetMem(D, Sizeof(D^)); Result.CustomData := D; D.FOnScroll := OnScroll; AParent.AttachProc(WndProcTrackbarParent); end; Начнем с переедаемых параметров - Parent, Visible, Orientation, OnScroll - думаю назначение ясно без комментариев, но достойны ли они идти в качестве постоянных "спутников жизни"? Без Родителя компонент не создать! Видимость можно указать на этапе создания - поэтому выносить ее отдельно не хочется. Ориентацию вообще можно установить только во время создания и поменять нельзя! Событие желательно прикреплять как можно раньше, ну что думаю, возражений нет. Строка: DoInitCommonControls( ICC_BAR_CLASSES ); нужна для инициализации "стандартных компонентов" (CommonControls - понятие API). begin DoInitCommonControls( ICC_BAR_CLASSES ); end. Тогда если TrackBar(ы) создается(ются) эта строка вызывается, если же нет, то KOL и MCK удалит сам модуль из uses и вызываться она не будет - оптимизация. Хотя есть еще мысль поручить вызов функции MCK части компонента (где-нибудь в SetupFirst) вроде того: procedure TKOLMHTrackBar.SetupFirst(SL: TStringList; const AName, AParent, Prefix: string); … begin SL.Add(' DoInitCommonControls( ICC_BAR_CLASSES );'); … Преимущества пока не совсем очевидны, но если договорится, веем оформлять подобные (с точки зрения количества вызовов) функции таким образом (в MCK части компонента) и перед добавлением данной строки осуществлять проверку на ее наличие, Result := PMHTrackbar(_NewCommonControl(AParent, TRACKBAR_CLASS, WS_CHILD or Visible2Style[Visible] or TBS_FIXEDLENGTH or TBS_ENABLESELRANGE or Orientation2Style[Orientation], False, 0));
GetMem(D, Sizeof(D^)); Result.CustomData := D; D.FOnScroll := OnScroll;
AParent.AttachProc(WndProcTrackbarParent);
function WndProcTrackbarParent( Sender: PControl; var Msg: TMsg; var Rslt: Integer ): Boolean; var D: PTrackbarData; Trackbar: PMHTrackbar; begin Result := FALSE; if (Msg.message = WM_HSCROLL) or (Msg.message = WM_VSCROLL) then if (Msg.lParam <> 0) then begin Trackbar := Pointer( GetProp( Msg.lParam, ID_SELF ) ); if Trackbar <> nil then begin D := Trackbar.CustomData; if Assigned( D.FOnScroll ) then D.FOnScroll( Trackbar, Msg.wParam ); end; end; end;
function TMHTrackbar.GetPosition: DWord; begin Result := Perform(TBM_GETPOS, 0, 0); end; procedure TMHTrackbar.SetPosition(const Value: DWord); begin Perform(TBM_SETPOS, 1, Value); end; А вот если API вернуть нынешнее состояние параметра не в состоянии, его предется сохранять в CustomData: function TMHTrackBar.GetOrientation: TTrackBarOrientation; begin Result := PTrackbarData(CustomData)^.FOrientation; end; procedure TMHTrackBar.SetOrientation(const Value: TTrackBarOrientation); begin PTrackbarData(CustomData)^.FOrientation := Value; Recreate; end; function TMHTrackbar.GetOnScroll: TOnScroll; var D: PTrackbarData; begin D := CustomData; Result := D.FOnScroll; end; procedure TMHTrackbar.SetOnScroll(const Value: TOnScroll); var D: PTrackbarData; begin D := CustomData; D.FOnScroll := Value; end;
property Min: DWord…; property Max: DWord …; property Position: DWord …; property SelStart: DWord …; property SelEnd: DWord …; property PageSize: DWord …; property LineSize: DWord …; property ThumbLength:DWord…; Как мы обычно делаем? SetMax/GetMax, SetMin/GetMin и пошло. А если подумать, они все одного типа. Теперь посмотрим на код функций и процедур Set/Get: function TMHTrackbar.GetPosition: DWord; begin Result := Perform(TBM_GETPOS, 0, 0); end; procedure TMHTrackbar.SetPosition(const Value: DWord); begin Perform(TBM_SETPOS, 1, Value); end; или вот: function TMHTrackbar.GetMax: DWord; begin Result := Perform(TBM_GETRANGEMIN, 0, 0); end; procedure TMHTrackbar.SetMin(const Value: DWord); begin Perform(TBM_SETRANGEMIN, 1, Value); end; Можно обобщить как: property Min: DWord index 0 read GetVal write SetVal; property Max: DWord index 1 read GetVal write SetVal; property Orientation: TTrackBarOrientation read GetOrientation write SetOrientation; property Position: DWord index 2 read GetVal write SetVal; property SelStart: DWord index 3 read GetVal write SetVal; property SelEnd: DWord index 4 read GetVal write SetVal; property PageSize: DWord index 5 read GetVal write SetVal; property LineSize: DWord index 6 read GetVal write SetVal; property ThumbLength: DWord index 7 read GetVal write SetVal; function TMHTrackbar.GetVal(const Index: Integer): DWord; type RVal = packed record Com: DWord; Par1: Byte; Par2: Byte; end; const Val: array [0..7] of RVal = ( (Com: TBM_GETRANGEMIN; Par1: 0; Par2: 0), (Com: TBM_GETRANGEMAX; Par1: 0; Par2: 0), (Com: TBM_GETPOS; Par1: 0; Par2: 0), (Com: TBM_GETSELSTART; Par1: 0; Par2: 0), (Com: TBM_GETSELEND; Par1: 0; Par2: 0), (Com: TBM_GETPAGESIZE; Par1: 0; Par2: 0), (Com: TBM_GETLINESIZE; Par1: 0; Par2: 0), (Com: TBM_GETTHUMBLENGTH; Par1: 0; Par2: 0) ); begin with Val[Index] do Result := Perform(Com, Par1, Par2); end; procedure TMHTrackbar.SetVal(const Index: Integer; const Value: DWord); type RVal = packed record Com: DWord; Use1: Byte; Use2: Byte; Par1: Byte; Par2: Byte; end; const Val: array [0..7] of RVal = ( (Com: TBM_SETRANGEMIN; Use1: 0; Use2: 1; Par1: 1; Par2: 0), (Com: TBM_SETRANGEMAX; Use1: 0; Use2: 1; Par1: 1; Par2: 0), (Com: TBM_SETPOS; Use1: 0; Use2: 1; Par1: 1; Par2: 0), (Com: TBM_SETSELSTART; Use1: 0; Use2: 1; Par1: 1; Par2: 0), (Com:TBM_SETSELEND; Use1:0; Use2:1; Par1:1; Par2: 0), (Com: TBM_SETPAGESIZE; Use1: 0; Use2: 1; Par1: 1; Par2: 0), (Com: TBM_SETLINESIZE; Use1: 0; Use2: 1; Par1: 1; Par2: 0), (Com: TBM_SETTHUMBLENGTH; Use1: 1; Use2: 0; Par1: 0; Par2: 0) ); begin with Val[Index] do Perform(Com, Value*Use1 + Par1, Value*Use2 + Par2); end; Как вам, вместо 14 методов 2? Статистику слегка портит THUMBLENGTH, но его можно выкинуть и упростить методы. Можно еще под Com выделять байт и сделать так: … (Com: TBM_SETRANGEMIN - WM_USER; Use1: 0; Use2: 1; Par1: 1; Par2: 0), … Perform(Com + WM_USER, Value*Use1 + Par1, Value*Use2 + Par2); Еще экономия. Вы можете сказать, что теперь код стал медленнее, это так, но не сильно - это раз, а во-вторых в деле графического интерфейса - это не самый критичный код (самый критичный отрисовка - а ей руководит ОС). Мда… маленькая вставочка - недаром я хотел ее в отдельную главу оформить. The article describes how to create a visual component for KOL and MCK, specifically a TrackBar component, by inheriting from TControl and using the API functions provided by the KOL library. And here ar Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
|
||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |