问题
I have made the UI/Editor you can see in the picture below. The Text is displayed by StyledText
s. The black lines are custom borders that are in fact Label
s with lines drawn on them.
Now my goal is to provide a selection that allows the user to select the Control
s to delete them or add others to them. The second image shows a example selection. So started with all kinds of MouseEvent
s this is more complicated than I initially thought.
When the MouseDown
event is fired on any Control
I am not able to track any other Control
s that the user wants to select because the MouseMove
event contains the same control that fired the MouseDown
event until the mouse gets released. I need to track to ongoing selection to provide the visual feedback for the selected Control
s. The code below shows a minimal example to demonstrate the behavior.
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;
}
}
}
}
So basically I am reaching out for help. Maybe there is a better/simpler way to achieve this. I was also trying to figure out how swt is doing this in tables or other controls that support multiple selection. But its hard to find the specific code or they call native methods for nativ controls such as tables. So if anyone has an idea please share.
回答1:
I found a solution for my problem. You can post a MouseUp
event yourself. After that all events are coming through again. The only difficult part is to distinguish between your own custom event and a normal user/system event. I was able create/find some criteria to identify the custom event. The following code/doc explains this in more detail:
/**
* 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;
}
来源:https://stackoverflow.com/questions/44526366/swt-mousedown-event-too-dominant-for-custom-selecting-controls