Другим часто задаваемым вопросом является "Как мне сделать реакцию на тройной щелчок или выше?". Когда вы увидели алгоритм для двойных щелчков, расширение его на щелчки более высоких порядков будет довольно естественным.
Первое вещью, которую вам, вероятно, следует сделать - убрать стиль CS_DBLCLKS из вашего класса, потому что вы хотите управлять щелчками вручную.
type TForm1 = class(TForm) ... protected { Protected declarations } procedure CreateParams(var Params: TCreateParams); override; end; procedure TForm1.CreateParams(var Params: TCreateParams); begin inherited; with Params.WindowClass do Style := Style and (not CS_DBLCLKS); end;
Далее вы просто реализуете тот же механизм, что и оконный менеджер, но только берёте большее число, а не два. Давайте сделаем это. Начнём с пустого VCL приложения, уберём у окна стиль CS_DBLCLKS и добавим следующее:
type TForm1 = class(TForm) ... private { Private declarations } g_rcClick: TRect; g_tmLastClick: DWORD; g_cClicks: Integer; procedure ResetClicks; end; procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Pt: TPoint; tmClick: DWORD; begin if Button = mbLeft then begin Pt.X := X; Pt.Y := Y; tmClick := GetMessageTime; if (not PtInRect(g_rcClick, pt)) or (tmClick - g_tmLastClick > GetDoubleClickTime) then g_cClicks := 0; Inc(g_cClicks); g_tmLastClick := tmClick; SetRect(g_rcClick, X, Y, X, Y); InflateRect(g_rcClick, GetSystemMetrics(SM_CXDOUBLECLK) div 2, GetSystemMetrics(SM_CYDOUBLECLK) div 2); Caption := IntToStr(g_cClicks); end else ResetClicks; end; procedure TForm1.ResetClicks; begin g_cClicks := 0; Caption := 'Form1'; end; procedure TForm1.FormActivate(Sender: TObject); begin ResetClicks; end;
Основная идея здесь проста: когда происходит клик, мы смотрим, находится ли он в "дабл-клик зоне" и произошёл ли он в период задержки дабл-клик. Если нет, то мы сбрасываем отсчёт щелчков.
(Заметьте, что значения SM_CXDOUBLECLK и SM_CYDOUBLECLK описывают зону целиком, так что мы обрезаем их наполовину, когда расширяем прямоугольник. Да, это означает, что мы теряем пиксель, если дабл-клик длина или высота нечётны, но Windows аккуратна и всегда ставит значения в чётные числа).
Потом мы записываем координаты и время текущего щелчка, чтобы потом сравнить следующий щелчок с ними.
Наконец, мы реагируем на щелчок, выводя соответствующий номер в заголовке окна (вместо этого мы могли бы вызывать OnClick, OnDblClick, OnTripleClick, OnQuadClick и т.д. - прим.пер.).
В этом коде есть несколько подводных камней. Во-первых, заметим, что установка g_cClicks в ноль заставит следующий щелчок рассматриваться как первый щелчок в серии, вне зависимости от его соответствия другим критериям, всё, что случится - счётчик кликов будет увеличен на 1.
Далее, заметим, что способ проверки попадания двух щелчков в интервал не чувствителен к переполнению тиков таймера. Если бы мы написали
if (not PtInRect(g_rcClick, pt)) or (tmClick > g_tmLastClick + GetDoubleClickTime) then
тогда мы бы не смогли правильно определить несколько тиков в момент около переполнения тиков таймера (убедитесь, что вы это поняли).
В-третьих, заметим, что мы сбрасываем счётчик, когда окно теряет или приобретает фокус. Таким образом, если пользователь щёлкает, затем переключает окна, и снова щёлкает, то эта последовательность не будет распознана как двойной щелчок. Мы поступаем аналогично для правой кнопки мыши (вы можете заметить, что не так много программ вообще учитывают эти тонкости).
Упражнение: предположим, что ваша программа не заинтересована в чём-либо, кроме тройных щелчков. Как бы вы изменили пример выше, способом, согласованным с тем, как оконный менеджер останавливается по двойным-щелчкам?
Немного потерялся смысл при переводе. После фразы "Далее, заметим, что способ проверки попадания двух щелчков в интервал не чувствителен к переполнению тиков таймера. Если бы мы написали..." в оригинале другой код.
ОтветитьУдалитьДьявол! :D Спасибо, поправил :)
ОтветитьУдалитьХотел избавиться от подчёркивания красным и вынес в добавку больше кода, чтобы было проще понять, о каком изменении идёт речь. В процессе Copy&Paste забыл про само изменение!