How to distinguish between click and double-click in opencv

2.7k views Asked by At

In OpenCV, it seems a double-click action also triggers a single-click event. Here is a sample code. The single_click() is always called before double_click().

Is it possible to trigger double_click() without triggering single_click() first?

Thanks!

void double_click() {
  std::cout << "Double click.\n";
}

void thisMouseCallBack(int event, int x, int y, int flags, void *param) {
  if (event == cv::EVENT_LBUTTONDOWN) {
    single_click();
  }
  if (event == cv::EVENT_LBUTTONDBLCLK) {
    double_click(); 
  }
}

int main() {
   cv::Mat testImg(100, 500, CV_8UC3); 
   cv::namedWindow("thisWindow");
   cv::setMouseCallback("thisWindow", thisMouseCallBack, NULL); 
   cv::imshow("thisWindow", testImg); 
   cv::waitKey(-1);
   return 0;
}
2

There are 2 answers

1
damian On

To distinguish double and single clicks (ie fire only the double-click event on double click, and skip the single click event), the standard way to do it uses a timer.

Start a timer (~100-200ms) on the first click, but do not call single_click. If the timer finishes before another click is received, call single_click. But if another click is received before the timer finishes, cancel the timer and call double_click.

However, as Rob Kennedy points out above, this will cause a small delay, so be careful about objects where you want to distinguish between single and double click. In most GUIs, single click is a select operation and double-click is an 'open' or 'execute' operation, so it makes sense to have to select an object before activating it.

0
NetworkSys Co. Ltd On

I wrote the following code and it works.

UINT TimerId;
int clicks;

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
    KillTimer(NULL, TimerId);
    if (clicks < 2 && !double_click){
        MessageBox(hWnd, L"Show Widget", L"Widget", MB_OK);
    }

    clicks = 0;
}



LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR szHello[MAX_LOADSTRING];
    LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
    UINT uID;
    UINT uMouseMsg;

    uID = (UINT)wParam;
    uMouseMsg = (UINT)lParam;

    if (uMouseMsg == WM_LBUTTONDBLCLK){
        double_click = true;
        MessageBox(hWnd, L"Double click", L"CAPT", MB_OK);
        return 0;
    }
    if (uMouseMsg == WM_LBUTTONDOWN){
        double_click = false;
        clicks++;

        //single click opens context menu
        if (clicks == 1){
            TimerId = SetTimer(NULL, 0, 500, &TimerProc);
        }
        return 0;
    }
,...
}