TButton:平均约105-116ms
timage:平均~220-235ms
我重复了几次,结果相似.为什么timage处理点击率大约是TButton的一半?处理从WM_LBUTTON_DOWN到OnClick事件的Windows消息队列会更慢吗?如果它们在前一次点击的N ms之内,它可能正在吞咽Clicks?
注意:如果相关,请使用Delphi 7和标准VCL控件.
编辑:这是一些示例代码,演示我如何计时:
// Define variables (in class deFinition) m_dwBtnClicks,m_dwImgClicks: DWORD; m_dwLastBtnClickTicks,m_dwLastImgClickTicks: DWORD; m_fTotalBtnClicksTicks,m_fTotalImgClicksTicks: Single; // Initialise variables (in form's OnCreate event) m_dwBtnClicks := 0; m_dwImgClicks := 0; m_dwLastBtnClickTicks := 0; m_dwLastImgClickTicks := 0; m_fTotalImgClicksTicks := 0.0; m_fTotalImgClicksTicks := 0.0; // OnClick events procedure TfrmQwerty.btnClick(Sender: TObject); var dwTime: DWORD; begin // TButton click! Inc(m_dwBtnClicks); dwTime := GetTickCount(); if (m_dwLastBtnClickTicks > 0) then m_fTotalBtnClicksTicks := (m_fTotalBtnClicksTicks + (dwTime - m_dwLastBtnClickTicks)); m_dwLastBtnClickTicks := dwTime; end; procedure TfrmQwerty.imgClick(Sender: TObject); var dwTime: DWORD; begin // timage click! Inc(m_dwImgClicks); dwTime := GetTickCount(); if (m_dwLastImgClickTicks > 0) then m_fTotalImgClicksTicks := (m_fTotalImgClicksTicks + (dwTime - m_dwLastImgClickTicks)); m_dwLastImgClickTicks := dwTime; end; // Some TTimer::OnTimer event to update the results on-screen procedure TfrmQwerty.OnTextEntryTimer(Sender: TObject); var fTime: Single; begin // Stop the timer TextEntryTimer.Enabled := False; if (m_dwBtnClicks > 1) then begin fTime := m_fTotalBtnClicksTicks / m_dwBtnClicks; lblButtonClicks.Caption := Format('BtnClicks = %d [Avg = %.3fms]',[ m_dwBtnClicks,fTime]); end; if (m_dwImgClicks > 1) then begin fTime := m_fTotalImgClicksTicks / m_dwImgClicks; lblImageClicks.Caption := Format('ImgClicks = %d [Avg = %.3fms]',[ m_dwImgClicks,fTime]); end; // Restart the timer TextEntryTimer.Enabled := True; end;
解决方法
让我们来看看点击足够快以触发双击时会发生什么:
第1步 – 鼠标左键按下:
procedure TControl.WMLButtonDown(var Message: TWMLButtonDown); begin SendCancelMode(Self); inherited; if csCaptureMouse in ControlStyle then MouseCapture := True; if csClickEvents in ControlStyle then // !! Note here Include(FControlState,csClicked); // Storing that we've been clicked DoMouseDown(Message,mbLeft,[]); end;
第2步 – 鼠标左键上升.
procedure TControl.WMLButtonUp(var Message: TWMLButtonUp); begin inherited; if csCaptureMouse in ControlStyle then MouseCapture := False; if csClicked in ControlState then // !! Note here begin // Firing CLICK event primed Exclude(FControlState,csClicked); // from the method above if ClientRect.Contains(SmallPointToPoint(Message.Pos)) then Click; end; DoMouseUp(Message,mbLeft); end;
第3步 – 鼠标左键再次下降.
这一次,它是双击!请注意,这是处理完全不同的消息 – 来自操作系统的双击消息,而不是鼠标按下消息.这里的处理程序仍然会触发MouseDown事件,但是当鼠标按钮重新启动时,它不会触发控件以触发click事件.
procedure TControl.WMLButtonDblClk(var Message: TWMLButtonDblClk); begin SendCancelMode(Self); inherited; if csCaptureMouse in ControlStyle then MouseCapture := True; if csClickEvents in ControlStyle then DblClick; DoMouseDown(Message,[ssDouble]); end;
由于Button是一个特殊的TWinControl,它会收到在单击按钮时生成的特殊BN_CLICKED消息,无论它是否是双击.作为一个简单的控件,它可以完成一项简单的工作,因此当您快速单击时(比双击率更快),您可以从按钮看到两倍的点击事件.
procedure TCustomButton.CNCommand(var Message: TWMCommand); begin if Message.NotifyCode = BN_CLICKED then Click; end;
您还可以注意到,由于TButton将接收这些特殊消息,因此在其ControlStyle中没有csClickEvents选项的情况下创建它,因此虽然它也是TControl,但上述用于timage(和其他)控件的步骤中的处理不会apply(即:为WMLButtonDown处理程序中的Click启动).
正如您所发现的,OnMouseDown或onmouseup事件将允许您捕获timage控件中的所有此类事件,无论它们是否应被视为单击或双击.
或者,如果您不关心timage处理双击,您可以将控件样式设置为:
Image1.ControlStyle := Image1.ControlStyle - [csDoubleClicks];
在这里,在TControl.WndProc中:
if not (csDoubleClicks in ControlStyle) then case Message.Msg of WM_LBUTTONDBLCLK,WM_RBUTTONDBLCLK,WM_MBUTTONDBLCLK: Dec(Message.Msg,WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); end;
您可以看到双击事件转换为简单的鼠标按下事件.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。