SWT MouseDown 事件对于自定义选择控件来说太重要了

SWT MouseDown event too dominant for custom selecting controls

我做了UI/Editor你可以在下面的图片中看到。文本显示 StyledTexts。黑线是自定义边框,实际上 Label 上面画有线条。

现在我的目标是提供一个 selection,允许用户 select Control 删除它们或向其中添加其他内容。第二张图片显示了一个示例 selection。所以从各种 MouseEvent 开始,这比我最初想象的要复杂。

MouseDown 事件在任何 Control 上触发时,我无法跟踪用户想要 select 的任何其他 Control,因为 MouseMove 事件包含触发 MouseDown 事件的相同控件,直到鼠标被释放。我需要跟踪正在进行的 selection 来为 selected Controls 提供视觉反馈。下面的代码显示了一个演示行为的最小示例。

public class Tester {

    public static void main(String[] args)
    {
        Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        shell.setText("Whosebug");

        Composite comp = new Composite(shell, SWT.NONE);
        comp.setLayout(new GridLayout(1, true));
        SelectionListener listener = new SelectionListener();

        StyledText text = new StyledText(comp, SWT.NONE);
        text.setText("first text");
        attachListener(text, listener);
        text = new StyledText(comp, SWT.NONE);
        text.setText("second text");
        attachListener(text, listener);


        shell.pack();
        shell.open();
        while (!shell.isDisposed())
        {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }

    private static void attachListener(Control control, Listener listener) {
        if(control != null && !control.isDisposed()){
            control.addListener(SWT.MouseDown, listener);
            control.addListener(SWT.MouseMove, listener);
            control.addListener(SWT.MouseEnter, listener);
            control.addListener(SWT.MouseUp, listener);
        }
    }

    static class SelectionListener implements Listener {

        Event lastEvent = null;

        @Override
        public void handleEvent(Event event) {
            switch(event.type){

            case SWT.MouseDown:
                lastEvent = event;
                break;

            case SWT.MouseMove:
                if(lastEvent != null){
                    if(event.widget == lastEvent.widget)
                        System.out.println("the same!!!");
                    else
                        System.out.println("not the same!!!");
                }
                break;

            case SWT.MouseEnter:
                //this also does not fire when MouseDown is fired
                System.out.println("entering");
                break;

            case SWT.MouseUp:
                lastEvent = null;
                break;
            }
        }

    }
}

所以基本上我是在寻求帮助。也许有一种 better/simpler 方法可以实现这一点。我还试图弄清楚 swt 如何在支持多个 selection 的表或其他控件中执行此操作。但是很难找到具体的代码,或者他们为表格等原生控件调用原生方法。所以如果有人有想法请分享。

我找到了解决问题的方法。您可以自己 post 举办 MouseUp 活动。在那之后,所有事件都再次发生。唯一困难的部分是区分您自己的自定义事件和正常的 user/system 事件。我能够 create/find 一些标准来识别自定义事件。以下code/doc对此进行了更详细的解释:

/**
     * Sets up a custom {@code SWT.MouseUp} event and fires it. This is needed because a {@code SWT.MouseDown} is consuming all
     * other events until a {@code SWT.MouseUp} event is fired. This means that it is not possible to get a e.g. 
     * {@code SWT.MouseEnter} event when entering a certain StyledText which is needed for selection. Therefore a custom {@code SWT.MouseUp} 
     * event is fired to simulate the releasing of the button on system level so that all other events can come through again. The real problem here
     * is to distinguish between the custom event for simulation and a normal event produced by the user. Firing the event via Display.post(Event)
     * does not fire the handed over event parameter. The system actually creates a new event instance. Therefore 2 criteria are used to distinguish the custom event:
     *  <ul>
     *      <ol>1. The selection can only be started by dragging a border control. 
     *          A {@code SWT.DragDetect} event starts the hole selection process. All events coming in before this event are ignored.</ol>
     *      <ol>2. The actual distinguishing of the {@code SWT.MouseUp} is performed on the cursor coordinates and the referenced/dragged {@code widget}.
     *          The dragging event has to be started on this widget.</ol>
     *  </ul>
     * @param the starting {@code SWT.DragDetect} event
     * @see #isCustomMouseUpEvent(Event)
     */
    private void fireCustomMouseUpEvent(Event dragDetectEvent){
        customMouseUpEvent = new Event();
        customMouseUpEvent.type = SWT.MouseUp;
        customMouseUpEvent.button = 1; //left mouse button
        customMouseUpEvent.widget = dragDetectEvent.widget;

        if(dragDetectEvent.widget instanceof Control){
            startingControl = (Control) dragDetectEvent.widget;
            //get cursor location relative to widget to be comparable later with the event fired by the system
            Point cursorLocation = startingControl.toControl(startingControl.getDisplay().getCursorLocation());
            customMouseUpEvent.x = cursorLocation.x;
            customMouseUpEvent.y = cursorLocation.y;
        }

        /*
         * note: set attributes like Event.data or Event.x are not present 
         * in the actually firing event. SWT or the system is creating a complete new
         * event instance without those manually added information.
         */
//      mouseUpEvent.data = SELECTION_START_EVENT_IDENTIFIER;
        if(dragDetectEvent.widget.getDisplay().post(customMouseUpEvent))
            System.out.println("custom MouseUp event fired!");
    }

    private boolean isCustomMouseUpEvent(Event event) {
        return customMouseUpEvent != null && event.widget == customMouseUpEvent.widget && 
                customMouseUpEvent.x == event.x && customMouseUpEvent.y == event.y;
    }