0

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;
}
Vince
  • 1
  • 1
  • 2
  • 1
    A double-click should *always* trigger a single-click; it's impossible to click twice without clicking once, after all. The alternative is to have slow-reacting single-click behavior because your program needs to wait after each click in case it might be followed by another click. Doing that will make your customers think your program is sluggish. Also, clicks are typically not registered until the mouse button is released, so calling your function after only receiving a mouse-down notification will make your program feel a little jumpy. Pay close attention to other programs you use each day. – Rob Kennedy Jan 27 '14 at 05:20

2 Answers2

3

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.

damian
  • 3,604
  • 1
  • 27
  • 46
  • @Vince If this answer solved your problem, you should accept it (By `clicking` the check mark in the left). – vyi Mar 24 '15 at 17:57
0

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;
    }
,...
}