[英]Delphi - Rate of clicking TImage slow compared with TButton
I have a form with both a TImage and a TButton control. 我有一个同时具有TImage和TButton控件的表单。 I noticed the rate of responding to the OnClick event seemed a bit slow for the TImage (rapid clicking!) so I measured it.
我注意到,对于TImage(快速单击!),对OnClick事件的响应速度似乎有点慢,因此我对其进行了测量。 For 100+ clicks (and clicking as fast as I could, keeping the rate as consistent as I could for each control) I got the metrics: TButton: Average ~105-116ms TImage: Average ~220-235ms
对于100次以上的点击(并尽可能快地单击,使每个控件的速率保持一致),我得到了指标:TButton:平均〜105-116ms TImage:平均〜220-235ms
I repeated this a few times with similar results. 我重复了几次,结果相似。 Why is the TImage processing clicks about half the rate of the TButton?
为什么TImage处理的点击率约为TButton的一半? Could it be slower to process the Windows message queue from WM_LBUTTON_DOWN to the OnClick event?
从WM_LBUTTON_DOWN到OnClick事件处理Windows消息队列会更慢吗? Maybe it is swallowing Clicks if they are within N ms of the previous click?
如果它们在上一次点击的N毫秒内,可能会吞下点击?
There's doesn't seem to be anything in the properties of the TImage that affects this. 在TImage的属性中似乎没有任何影响它的东西。
Note: Using Delphi 7 and the standard VCL controls here, if that is relevant. 注意:如果需要,请在此处使用Delphi 7和标准VCL控件。
EDIT: Here is some example code demonstrating how I timed things: 编辑:这是一些示例代码,展示了我如何定时事情:
// 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;
The VCL source is your friend here. VCL来源是您的朋友。 As noted, this is caused by double click messages being sent by Windows when clicking fast enough to generate them.
如前所述,这是由Windows在足够快地单击以生成消息时发送的双击消息引起的。
Let's look at what happens when clicking fast enough to trigger a double click: 让我们看看单击足够快以触发双击时会发生什么:
Step 1 - Left mouse button goes down : 步骤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;
Step 2 - Left mouse button goes up . 步骤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;
Step 3 - Left mouse button goes down again. 步骤3- 鼠标左键再次下降。
This time, it's a double click! 这次是双击! Note that this is handling an entirely different message - a double click message from the OS, not a mouse down message.
请注意,这是在处理完全不同的消息-来自操作系统的双击消息,而不是鼠标按下消息。 The handler here still fires the
MouseDown
event, but does not prime the control to fire a click event when the mouse button comes back up. 此处的处理程序仍然会触发
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, mbLeft, [ssDouble]);
end;
Since a Button is a special TWinControl
it receives the special BN_CLICKED
message that is generated any time the button is clicked, regardless of whether it might be a double click or not. 由于Button是特殊的
TWinControl
因此它会收到在单击该按钮时生成的特殊BN_CLICKED
消息,而不管它是否是双击。 Being a simple control it does a simple job and you therefore see twice as many click events from a button when clicking quickly (faster than the double-click rate). 作为一个简单的控件,它可以完成简单的工作,因此,在快速单击时(比双击速度更快),您从按钮上看到的单击事件是其两倍。
procedure TCustomButton.CNCommand(var Message: TWMCommand);
begin
if Message.NotifyCode = BN_CLICKED then Click;
end;
You can also note that, since a TButton
will receive these special messages it is created without the csClickEvents
option in its ControlStyle
, so although it is also a TControl
, the handling in the above steps used for the TImage
(and other) controls does not apply (ie: priming for the Click
in the WMLButtonDown
handler). 您也可以注意到,因为
TButton
将收到它没有创建这些特殊的信息csClickEvents
在其选项ControlStyle
,所以虽然它也是一个TControl
,用于在以上步骤处理TImage
(等)控制不应用(即:为WMLButtonDown
处理程序中的Click
启动)。
As you have discovered, the OnMouseDown
or OnMouseUp
events will allow you to capture all such events in your TImage
control, regardless of whether they should be treated as clicks or double clicks. 正如您所发现的,
OnMouseDown
或OnMouseUp
事件将使您能够捕获TImage
控件中的所有此类事件,而不管它们应被视为单击还是双击。
Alternatively, if you don't care about your TImage
processing double clicks you can set the control style as : 另外,如果您不关心双击
TImage
处理,则可以将控件样式设置为:
Image1.ControlStyle := Image1.ControlStyle - [csDoubleClicks];
Here, in the TControl.WndProc
: 在这里,在
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;
You can see the double click events are transformed to simple mouse down events. 您可以看到双击事件已转换为简单的鼠标按下事件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.