2015-06-01 14 views
5

Ich habe ein Formular mit einem TImage- und einem TButton-Steuerelement. Ich bemerkte, dass die Geschwindigkeit, mit der auf das OnClick-Ereignis reagiert wurde, für die TImage ein wenig langsam war (schnelles Klicken!), Also habe ich es gemessen. Für mehr als 100 Klicks Ich habe die Metriken (und so schnell wie ich konnte, hält die Raten so konsequent wie ich kann, für jeden Steuer klicken): TButton: Durchschnittlich ~ 105-116ms TImage: Durchschnitt ~ 220-235msDelphi - Klickrate TImage langsam im Vergleich zu TButton

Ich wiederholte dies einige Male mit ähnlichen Ergebnissen. Warum klickt die TImage-Verarbeitung ungefähr halb so schnell wie TButton? Könnte es langsamer sein, die Windows-Nachrichtenwarteschlange von WM_LBUTTON_DOWN zum OnClick-Ereignis zu verarbeiten? Vielleicht schluckt es Klicks, wenn sie innerhalb von N ms des vorherigen Klicks liegen?

Es scheint nichts in den Eigenschaften von TImage zu sein, das dies beeinflusst.

Hinweis: Verwenden Sie hier Delphi 7 und die VCL-Standardsteuerelemente, falls dies relevant ist.

EDIT: Hier ist ein Beispiel-Code demonstriert, wie ich die Dinge timed:

// 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; 
+0

Was haben Sie Timing? Bitte zeigen Sie ein kurzes Demo-Programm, das uns genau das gleiche Timing ermöglicht. –

+2

'TButton' verwendet [' BN_CLICKED'] (https://msdn.microsoft.com/en-us/library/windows/desktop/bb761825%28v=vs.85%29.aspx) Systembenachrichtigung zum Auslösen von 'OnClick' Ereignis, während 'TImage' nur Mouse-Down-/Mouse-Up-Ereignispaare verfolgt, also wäre ich nicht überrascht, dass es Unterschiede geben kann. – TLama

+0

@DavidHeffernan: OK, einige Beispielcode hinzugefügt, um zu zeigen, wie die Dinge zeitlich festgelegt wurden. Nichts Außergewöhnliches. Ich habe den TButton durch eine TImage auf einer QWERTY-ähnlichen Bildschirmtastatur ersetzt, als ich den großen Unterschied bemerkte. – AlainD

Antwort

4

Die VCL Quelle ist dein Freund hier. Wie bereits erwähnt, wird dies durch Doppelklick-Nachrichten verursacht, die von Windows gesendet werden, wenn sie schnell genug klicken, um sie zu generieren.

die bei Let schauen, was passiert, wenn schnell genug Klicken auf einen Doppelklick auslösen:

Schritt 1 - Linke Maustaste geht nach unten:

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; 

Schritt 2 - Linke Maustaste nach oben geht.

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; 

Schritt 3 - Linke Maustaste geht wieder nach unten.

Diesmal ist es ein Doppelklick! Beachten Sie, dass dies eine ganz andere Nachricht behandelt - eine Doppelklick-Nachricht vom Betriebssystem, keine Maus-unten-Nachricht. Der Handler hier löst weiterhin das Ereignis MouseDown aus, aber startet das Steuerelement nicht, um ein Klickereignis auszulösen, wenn die Maustaste wieder gedrückt wird.

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; 

Da ein Knopf ist ein spezieller TWinControl es die besondere BN_CLICKED Nachricht empfängt, die zu jeder Zeit erzeugt wird, auf die Schaltfläche geklickt wird, unabhängig davon, ob es sich um ein Doppelklick auf sein könnte oder nicht. Da es sich um ein einfaches Steuerelement handelt, ist es ein einfacher Job und Sie sehen daher doppelt so viele Klickereignisse von einer Schaltfläche, wenn Sie schnell klicken (schneller als die Doppelklickrate).

procedure TCustomButton.CNCommand(var Message: TWMCommand); 
begin 
    if Message.NotifyCode = BN_CLICKED then Click; 
end; 

Sie können auch zur Kenntnis, dass da ein TButton diese speziellen Nachrichten empfangen wird ohne die csClickEvents Option in seinem ControlStyle erstellt wird, so dass, obwohl es auch eine TControl ist, für die Handhabung in den obigen Schritten die TImage (und andere) Kontrollen gelten nicht (dh: Priming für die Click in der WMLButtonDown Handler).

Wie Sie entdeckt haben, die OnMouseDown oder OnMouseUp Ereignisse ermöglicht es Ihnen, alle diese Ereignisse in Ihrem TImage Kontrolle zu erfassen, unabhängig davon, ob sie als Klicks oder Doppelklicks behandelt werden.


Alternativ, wenn Sie nicht über Ihre TImage Verarbeitung Doppelklicks egal können Sie die Kontrolle Stil nach:

Image1.ControlStyle := Image1.ControlStyle - [csDoubleClicks]; 

Hier im 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; 

Sie kann sehen, dass die Doppelklickereignisse in einfache Mausereignisse umgewandelt werden.

+0

Klickereignisse treten bei Mausbewegung statt Mausbewegung auf. –

+0

@DavidHeffernan Ich glaube nicht, dass ich etwas anderes gesagt habe. Es sei denn du meinst den Doppelklick, was bei Mouse Down definitiv passiert. –

+0

Sie haben gesagt: * Wie Sie festgestellt haben, können Sie mit dem 'OnMouseDown'-Ereignis alle Maus-Down-Ereignisse erfassen ... unabhängig davon, ob sie als Klicks oder Doppelklicks behandelt werden. * –

Verwandte Themen