Например, необходимо создать специализированный редактор, с помощью которого можно было бы изменять координаты типа TPoint. При нажатии клавиши ввода будет происходить некоторое пользовательское событие, а при нажатии клавиши Esc – обнуление координат.
В принципе для этого вполне подходит TMaskEdit, но было бы удобней, если бы у компонента было бы свойство, обращаясь к которому можно было бы получить координаты точки.
Так и сделаем. Создадим новый компонент, унаследованный от TCustomMaskEdit, с одной стороны способный контролировать клавиатурный ввод по маске, а с другой – не отягощенный опубликованными свойствами и событиями.
Для начала определим новое свойство типа TPoint:
property EditPoint: TPoint read GetPoint write SetPoint;
Затем переопределим конструктор, в котором сразу установим требуемую маску ввода данных и начальное значение координат:
constructor TPointEdit.Create(AOwner: TComponent); begin inherited; EditMask:='9990, 9990;1; '; EditPoint:=Point(0,0); end;
Метод записи свойства EditPoint определим таким образом, чтобы при установке его извне свойство Text выглядело бы корректно. Сделаем это с помощью функции Format:
procedure TPointEdit.SetPoint(const Value: TPoint); begin Text:=Format('%4d, %4d',[Value.X, Value.Y]); end;
Метод чтения свойства EditPoint напишем таким образом, чтобы значение получалось из сформатированного текста:
function TPointEdit.GetPoint: TPoint; var CommaPos: Integer; begin CommaPos:=pos(',',Text); Result:=Point(StrToInt(Copy(Text,1,CommaPos-1)), StrToInt(Copy(Text,CommaPos+1,length(Text)))); end;
Добавим новый тип события, упрощающего обработку координат, метод сообщения WM_KEYDOWN, вызывающийся каждый раз при нажатии клавиши:
TOnNewPoint=procedure(Sender: TPointEdit; Point:TPoint) of object; … published property OnNewPoint:TOnNewPoint read FOnNewPoint write FOnNewPoint; procedure WMKeyDown(var M:TWMKey); message WM_KEYDOWN; … procedure TPointEdit.WMKeyDown(var M: TWMKey); begin inherited; if (M.CharCode=VK_RETURN) then begin Invalidate; if Assigned(FOnNewPoint) then FOnNewPoint(Self as TPointEdit, GetPoint); end; if (M.CharCode=VK_ESCAPE) then EditPoint:=Point(0,0); end;
Обратите внимание, что обработка ввода происходит только при нажатии клавиши ввода, нажатие же клавиши Esc приводит к обнулению значения координат.
Создадим тестовое приложение, демонстрирующее работу нового компонента, в котором координаты некоторого компонента меняются при изменении свойства EditPoint.
Пример 7.5. Пример реализации компонента-наследника TListBox с горизонтальной прокруткой
unit ScrollListBox; interface uses SysUtils, Classes, Controls, StdCtrls, Windows, Messages, Dialogs; type TOnEnabledChange=procedure(Sender: TObject; Enabled:boolean) of object; TScrollListBox = class(TListBox) private FHorizontExtent: word; FOnEnabledChange: TOnEnabledChange; { Private declarations } procedure GetLongestString; procedure LBAddString(var Msg:TMessage); message lb_AddString; procedure LBInsertString(var Msg:TMessage); message lb_InsertString; procedure LBDeleteString(var Msg:TMessage); message lb_DeleteString; procedure WMEnable (var M:TWMEnable); message WM_Enable; protected { Protected declarations } procedure CreateParams(var Params: TCreateParams); override; procedure CreateWnd; override; public { Public declarations } published { Published declarations } property OnEnabledChange: TOnEnabledChange read FOnEnabledChange write fOnEnabledChange; end; procedure Register; implementation uses Math; procedure Register; begin RegisterComponents('Лекция 6', [TScrollListBox]); end; { TScrollListBox } procedure TScrollListBox.CreateParams(var Params: TCreateParams); begin inherited; Params.Style:=Params.Style or WS_HSCROLL; end; procedure TScrollListBox.CreateWnd; begin inherited; Perform(LB_SETHORIZONTALEXTENT,2,0); ShowScrollBar(Handle,SB_HORZ,true) end; procedure TScrollListBox.GetLongestString; var i: integer; begin FHorizontExtent:=0; Canvas.Font.Assign(font); for i :=0 to Items.count-1 do FHorizontExtent:=Max(FHorizontExtent,Canvas.TextWidth(Items[i])); Perform(LB_SETHORIZONTALEXTENT,FHorizontExtent+2,0); end; procedure TScrollListBox.LBAddString(var Msg: TMessage); begin inherited; GetLongestString; end; procedure TScrollListBox.LBDeleteString(var Msg: TMessage); begin inherited; GetLongestString; end; procedure TScrollListBox.LBInsertString(var Msg: TMessage); begin inherited; GetLongestString; end; procedure TScrollListBox.WMEnable(var M: TWMEnable); begin inherited; if Assigned(FOnEnabledChange) then FOnEnabledChange(Self, Enabled); end; end.