加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Delphi – 与TButton相比,点击TImage的速度较慢

发布时间:2020-12-15 09:28:48 所属栏目:大数据 来源:网络整理
导读:我有一个包含T Image和TButton控件的表单.我注意到响应OnClick事件的速度对于TImage来说似乎有点慢(快速点击!)所以我测量了它.点击100次(并尽可能快地点击,保持每个控件的速率尽可能一致)我得到了指标: TButton:平均约105-116ms TImage:平均~220-235ms
我有一个包含T Image和TButton控件的表单.我注意到响应OnClick事件的速度对于TImage来说似乎有点慢(快速点击!)所以我测量了它.点击100次(并尽可能快地点击,保持每个控件的速率尽可能一致)我得到了指标:
TButton:平均约105-116ms
TImage:平均~220-235ms

我重复了几次,结果相似.为什么TImage处理点击率大约是TButton的一半?处理从WM_LBUTTON_DOWN到OnClick事件的Windows消息队列会更慢吗?如果它们在前一次点击的N ms之内,它可能正在吞咽Clicks?

TImage的属性似乎没有任何影响这一点的东西.

注意:如果相关,请使用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;

解决方法

VCL来源是你的朋友.如上所述,这是由Windows单击足够快速生成它们时发送的双击消息引起的.

让我们来看看点击足够快以触发双击时会发生什么:

第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;

您可以看到双击事件转换为简单的鼠标按下事件.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读