MouseDown events are not delivered until MouseUp when a Drag Source is present

大城市里の小女人 提交于 2019-12-04 22:51:51

To answer your specific question about why this happens -- on Cocoa we don't consider a drag to have started until the mouse has moved a few pixels. This ensures against 'accidental' drags if you're sloppy with the clicks. On Linux and Win32 the window toolkit can do the drag detection. If you just hold down the button the detection times out and the mouse down is delivered. On Cocoa we have no time out, which is why nothing happens until the drag is detected or a mouse up happens.

That's a lot of detail, but the conclusion is that the behavior is inconsistent, and we should always be able to deliver the mouse down immediately, without waiting for the drag detection to complete.

I don't see a workaround, since this is happening before the Control sees the event.

See this bug which has patches for win32, gtk and cocoa SWT.

I had faced the same problem and found a solution. Once you attach a DragSource to your custom widget, the event loop will be blocked in that widget's mouse down hook and will eat mouse move events to detect a drag. (I've only looked into the GTK code of SWT to find this out, so it may work a little differently on other platforms, but my solution works on GTK, Win32 and Cocoa.) In my situation, I wasn't so much interested in detecting the mouse down event right when it happened, but I was interested in significantly reducing the drag detection delay, since the whole purpose of my Canvas implementation was for the user to drag stuff. To turn off the event loop blocking and built-in drag detection, all you have to do is:

setDragDetect(false);

In my code, I am doing this before attaching the DragSource. As you already pointed out, this will leave you with the problem that you can't initiate a drag anymore. But I have found a solution for that as well. Luckily, the drag event generation is pure Java and not platform specific in SWT (only the drag detection is). So you can just generate your own DragDetect event at a time when it is convenient for you. I have attached a MouseMoveListener to my Canvas, and it stores the last mouse position, the accumulated drag distance and whether or not it already generated a DragDetect event (among other useful things). This is the mouseMove() implementation:

public void mouseMove(MouseEvent e) {
    if (/* some condition that tell you are expecting a drag*/) {

        int deltaX = fLastMouseX - e.x;
        int deltaY = fLastMouseY - e.y;

        fDragDistance += deltaX * deltaX + deltaY * deltaY;

        if (!fDragEventGenerated && fDragDistance > 3) {
            fDragEventGenerated = true;

            // Create drag event and notify listeners.
            Event event = new Event();
            event.type = SWT.DragDetect;
            event.display = getDisplay();
            event.widget = /* your Canvas class */.this;
            event.button = e.button;
            event.stateMask = e.stateMask;
            event.time = e.time;
            event.x = e.x;
            event.y = e.y;
            if ((getStyle() & SWT.MIRRORED) != 0)
                event.x = getBounds().width - event.x;

            notifyListeners(SWT.DragDetect, event);
        }
    }

    fLastMouseX = e.x;
    fLastMouseY = e.y;
}

And that will replace the built-in, blocking drag detection for you.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!