Забавное программирование в Delphi


Забавное программирование в Delphi


Приведённый здесь материал можно озаглавить не иначе как "Чем заняться
программисту, если нечего делать". На самом деле,
Delphi настолько
интересная среда, что в ней наряду
с разработкой серьёзных
приложений
можно легко увлечься созданием абсолютно бесполезных
вещей.

Итак, поехали...

Автоматически нажимающаяся
кнопка
Этот компонент представляет из себя кнопку, на которую не надо
нажимать, чтобы получить событие OnClick. Достаточно переместить курсор мышки на
кнопку. При создании такого компонента традиционным способом, требуется довольно
много времени, так как необходимо обрабатывать мышку, перехватывать её и т.д.
Однако результат стоит того!

Предлагаю взглянуть на две версии данного
компонента.
В более простой версии обработчик перемещения мышки просто
перехватывает сообщения

Windows с нужным кодом и вызывает обработчик события OnClick:



Code
type
TAutoButton1 = class(TButton)
private
procedure WmMouseMove (var Msg: TMessage);
message wm_MouseMove;
end;
   
procedure TAutoButton1.WmMouseMove (var Msg: TMessage);
begin
inherited;
if Assigned (OnClick) then
OnClick (self);
end;


DRKB Explorer
Забавное программирование в Delphi
01.01.2007
Забавное программирование в Delphi

Приведённый здесь материал можно озаглавить не иначе как "Чем заняться программисту, если нечего делать". На самом деле,
Delphi настолько интересная среда, что в ней наряду
с разработкой серьёзных приложений
можно легко увлечься созданием абсолютно бесполезных вещей.

Итак, поехали...

Автоматически нажимающаяся кнопка
Этот компонент представляет из себя кнопку, на которую не надо нажимать, чтобы получить событие OnClick. Достаточно переместить курсор мышки на кнопку. При создании такого компонента традиционным способом, требуется довольно много времени, так как необходимо обрабатывать мышку, перехватывать её и т.д. Однако результат стоит того!

Предлагаю взглянуть на две версии данного компонента.
В более простой версии обработчик перемещения мышки просто перехватывает сообщения

Windows с нужным кодом и вызывает обработчик события OnClick:

Code
type  
TAutoButton1 = class(TButton)  
private  
procedure WmMouseMove (var Msg: TMessage);  
message wm_MouseMove;  
end;  
   
procedure TAutoButton1.WmMouseMove (var Msg: TMessage);  
begin  
inherited;  
if Assigned (OnClick) then  
OnClick (self);  
end;  

type
TAutoButton1 = class(TButton)
private
procedure WmMouseMove (var Msg: TMessage);
message wm_MouseMove;
end;
   
procedure TAutoButton1.WmMouseMove (var Msg: TMessage);
begin
inherited;
if Assigned (OnClick) then
OnClick (self);
end;


Вторая версии имеет больше исходного кода,
так как в ней я просто пытаюсь повторить событие
мышки OnClick когда пользователь перемещает мышку над кнопкой либо по истечении

определённого времени. Далее следует объявление класса:
Code
type  
TAutoKind = (akTime, akMovement, akBoth);  
   
TAutoButton2 = class(TButton)  
private  
FAutoKind: TAutoKind;  
FMovements: Integer;  
FSeconds: Integer;  
// really private  
CurrMov: Integer;  
Capture: Boolean;  
MyTimer: TTimer;  
procedure EndCapture;  
// обработчики сообщений  
procedure WmMouseMove (var Msg: TWMMouse);  
message wm_MouseMove;  
procedure TimerProc (Sender: TObject);  
procedure WmLBUttonDown (var Msg: TMessage);  
message wm_LBUttonDown;  
procedure WmLButtonUp (var Msg: TMessage);  
message wm_LButtonUp;  
public  
constructor Create (AOwner: TComponent); override;  
published  
property AutoKind: TAutoKind  
read FAutoKind write FAutoKind default akTime;  
property Movements: Integer  
read FMovements write FMovements default 5;  
property Seconds: Integer  
read FSeconds write FSeconds default 10;  
end;


Итак, когда курсор мышки попадает в область кнопки (WmMouseMove), то компонент
запускает таймер либо счётчик количества сообщений о перемещении.
По истечении определённого времени либо при получении нужного количества сообщений о перемещении,
компонент эмулирует событие нажатия кнопкой.

Code
procedure TAutoButton2.WmMouseMove (var Msg: TWMMouse);  
begin  
inherited;  
if not Capture then  
begin  
SetCapture (Handle);  
Capture := True;  
CurrMov := 0;  
if FAutoKind <> akMovement then  
begin  
MyTimer := TTimer.Create (Parent);  
if FSeconds <> 0 then  
MyTimer.Interval := 3000  
else  
MyTimer.Interval := FSeconds * 1000;  
MyTimer.OnTimer := TimerProc;  
MyTimer.Enabled := True;  
end;  
end  
else // захватываем  
begin  
if (Msg.XPos > 0) and (Msg.XPos < Width)  
and (Msg.YPos > 0) and (Msg.YPos < Height) then  
begin  
// если мы подсчитываем кол-во движений...  
if FAutoKind <> akTime then  
begin  
Inc (CurrMov);  
if CurrMov >= FMovements then  
begin  
if Assigned (OnClick) then  
OnClick (self);  
EndCapture;  
end;  
end;  
end  
else // за пределами... стоп!  
EndCapture;  
end;  
end;  
   
procedure TAutoButton2.EndCapture;  
begin  
Capture := False;  
ReleaseCapture;  
if Assigned (MyTimer) then  
begin  
MyTimer.Enabled := False;  
MyTimer.Free;  
MyTimer := nil;  
end;  
end;  
   
procedure TAutoButton2.TimerProc (Sender: TObject);  
begin  
if Assigned (OnClick) then  
OnClick (self);  
EndCapture;  
end;  
   
procedure TAutoButton2.WmLBUttonDown (var Msg: TMessage);  
begin  
if not Capture then  
inherited;  
end;  
   
procedure TAutoButton2.WmLButtonUp (var Msg: TMessage);  
begin  
if not Capture then  
inherited;  
end;  


Как осуществить ввод текста в компоненте Label ?
Многие программисты задавая такой вопрос получают на него стандартный ответ "используй edit box."
На самом же деле этот вопрос вполне решаем, хотя лейблы и не основаны на окне и,
соответственно не могут получать фокус ввода и, соответственно не могут получать символы,
вводимые с клавиатуры. Давайте рассмотрим шаги, которые были предприняты мной для
разработки данного компонента.


Первый шаг, это кнопка, которая может отображать вводимый текст:

Code
type  
TInputButton = class(TButton)  
private  
procedure WmChar (var Msg: TWMChar);  
message wm_Char;  
end;  
   
procedure TInputButton.WmChar (var Msg: TWMChar);  
var  
Temp: String;  
begin  
if Char (Msg.CharCode) = #8 then  
begin  
Temp := Caption;  
Delete (Temp, Length (Temp), 1);  
Caption := Temp;  
end  
else  
Caption := Caption + Char (Msg.CharCode);  
end;  


С меткой (label) дела обстоят немного сложнее, так как прийдётся создать некоторые ухищрения,
чтобы обойти её внутреннюю структуру. Впринципе, проблему можно решить созданием других

скрытых компонент (кстати, тот же edit box). Итак, посмотрим на объявление класса:

Code
type  
TInputLabel = class (TLabel)  
private  
MyEdit: TEdit;  
procedure WMLButtonDown (var Msg: TMessage);  
message wm_LButtonDown;  
protected  
procedure EditChange (Sender: TObject);  
procedure EditExit (Sender: TObject);  
public  
constructor Create (AOwner: TComponent); override;  
end;  


Когда метка (label) создана, то она в свою очередь создаёт edit box и устанавливает несколько обработчиков событий для него. Фактически, если пользователь кликает по метке, то фокус перемещается на (невидимый) edit box, и мы используем его события для обновления метки. Обратите внимание на ту часть кода, которая подражает фокусу для метки (рисует прямоугольничек), основанная на API функции DrawFocusRect:

Code
constructor TInputLabel.Create (AOwner: TComponent);  
begin  
inherited Create (AOwner);  
   
MyEdit := TEdit.Create (AOwner);  
MyEdit.Parent := AOwner as TForm;  
MyEdit.Width := 0;  
MyEdit.Height := 0;  
MyEdit.TabStop := False;  
MyEdit.OnChange := EditChange;  
MyEdit.OnExit := EditExit;  
end;  
   
procedure TInputLabel.WMLButtonDown (var Msg: TMessage);  
begin  
MyEdit.SetFocus;  
MyEdit.Text := Caption;  
(Owner as TForm).Canvas.DrawFocusRect (BoundsRect);  
end;  
   
procedure TInputLabel.EditChange (Sender: TObject);  
begin  
Caption := MyEdit.Text;  
Invalidate;  
Update;  
(Owner as TForm).Canvas.DrawFocusRect (BoundsRect);  
end;  
   
procedure TInputLabel.EditExit (Sender: TObject);  
begin  
(Owner as TForm).Invalidate;  
end;  
Категория: Уроки по Delphi | Добавил: Dogvill (19.06.2012)
Просмотров: 669 | Рейтинг: 5.0/1
Всего комментариев: 0
Имя *:
Email:
Код *: