SWT MouseDown事件对于自定义选择控件来说太占优势

时间:2017-06-13 15:57:14

标签: java swt mouseevent multipleselection

我已经制作了你可以在下面的图片中看到的UI /编辑器。文本由StyledText显示。黑色线条是自定义边框,实际上是Label,并在其上绘制了线条。

unselected

selected

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

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

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("Stackoverflow");

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

    }
}

所以基本上我正在寻求帮助。也许有更好/更简单的方法来实现这一目标。我还试图弄清楚swt是如何在表或其他支持多选的控件中做到这一点的。但很难找到具体的代码,或者他们称本地方法为nativ控件,如表。所以如果有人有想法请分享。

1 个答案:

答案 0 :(得分:1)

我找到了解决问题的方法。您可以自己发布MouseUp个活动。之后所有事件都会再次发生。唯一困难的部分是区分您自己的自定义事件和普通用户/系统事件。我能够创建/找到一些标准来识别自定义事件。以下代码/ 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;
    }