2010-10-11 16 views
17

Tôi có một người nghe chuột. Nó có một số mã để trả lời các sự kiện mouseUp và mouseDown. Điều này hoạt động chính xác.Sự kiện MouseDown không được phân phối cho đến khi MouseUp khi có Nguồn Kéo

Tuy nhiên, ngay sau khi tôi thêm một DragSource, sự kiện mouseDown của tôi không còn được gửi nữa - cho đến khi tôi nhả chuột!

Điều này là tầm thường để tái tạo - dưới đây là một chương trình đơn giản có chứa một trình bao đơn giản chỉ với một người nghe chuột và một người nghe kéo. Khi tôi chạy (trên máy Mac), và tôi nhấn và giữ nút chuột, không có gì xảy ra - nhưng ngay sau khi tôi nhả nút chuột, tôi ngay lập tức nhìn thấy cả chuột và chuột lên các sự kiện được phân phối. Nếu tôi nhận xét ra nguồn kéo, thì các sự kiện chuột sẽ được phân phối theo cách của chúng.

Tôi đã tìm kiếm những người khác với vấn đề tương tự, và gần nhất tôi đã tìm thấy một lời giải thích là thế này:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=26605#c16 "Nếu bạn treo kéo phát hiện, hệ điều hành cần phải ăn các sự kiện chuột cho đến khi nó xác định rằng bạn đã kéo hay không. "

Tuy nhiên, tôi không hiểu tại sao điều đó đúng - tại sao hệ điều hành lại phải ăn các sự kiện chuột để xác định xem tôi có kéo hay không? Kéo không bắt đầu cho đến khi tôi có một sự kiện chuột-chuột với nút được nhấn.

Quan trọng hơn: Có ai có thể đề xuất cách giải quyết khác không? (Tôi đã thử tự động thêm và xóa nguồn kéo của mình khi nhấn chuột, nhưng sau đó tôi không thể kéo thả & để hoạt động chính xác vì nó không bao giờ thấy phím bấm ban đầu - và tôi không thể tìm cách khởi tạo chương trình . drag)

đây là chương trình mẫu:

package swttest; 

    import org.eclipse.swt.dnd.DND; 
    import org.eclipse.swt.dnd.DragSource; 
    import org.eclipse.swt.dnd.DragSourceEvent; 
    import org.eclipse.swt.dnd.DragSourceListener; 
    import org.eclipse.swt.events.MouseEvent; 
    import org.eclipse.swt.events.MouseListener; 
    import org.eclipse.swt.widgets.Display; 
    import org.eclipse.swt.widgets.Shell; 

    public class SwtTest { 
     public static void main(String[] args) { 
      final Display display = new Display(); 
      final Shell shell = new Shell(display); 
      shell.addMouseListener(new MouseListener() { 
       public void mouseUp(MouseEvent e) { 
        System.out.println("mouseUp"); 
       } 

       public void mouseDown(MouseEvent e) { 
        System.out.println("mouseDown"); 
       } 

       public void mouseDoubleClick(MouseEvent e) { 
        System.out.println("mouseDoubleClick"); 
       } 
      }); 
      DragSourceListener dragListener = new DragSourceListener() { 

       public void dragFinished(DragSourceEvent event) { 
        System.out.println("dragFinished"); 

       } 

       public void dragSetData(DragSourceEvent event) { 
        System.out.println("dragSetData"); 

       } 

       public void dragStart(DragSourceEvent event) { 
        System.out.println("dragStart"); 
       } 
      }; 
      DragSource dragSource = new DragSource(shell, DND.DROP_COPY | DND.DROP_MOVE); 
      dragSource.addDragListener(dragListener); 
      shell.pack(); 
      shell.open(); 
      while (!shell.isDisposed()) { 
       if (!display.readAndDispatch()) 
        display.sleep(); 
      } 
      display.dispose(); 
     } 
    } 
+0

Tôi đã thử và mã của bạn đang hoạt động trên Windows. Có thể là lỗi hệ điều hành cụ thể – nanda

+0

Tôi vừa thử trên Ubuntu 10.04 và sắp xếp các tác phẩm. Nhấn nút chuột trái bạn sẽ không nhận được sự kiện nào. Di chuyển chuột bạn nhận được 'mouseDown' và' dragStart' * cùng một lúc *. Khi bạn cho phép bạn nhận được sự kiện 'mouseUp'. Nếu bạn giữ chuột vẫn còn và nhấn nút trái, bạn sẽ nhận được một 'mouseDown' sau một sự chậm trễ đáng chú ý 1-2 giây. Dù bằng cách nào, 'mouseDown' luôn được nhìn thấy trước khi buông chuột. Phải là một SWT trên máy Mac? – richq

+0

Cảm ơn cả hai - có vẻ như đây chắc chắn là nền tảng cụ thể. Tuy nhiên, có vẻ như nó khá bị hỏng trên Linux quá - một giây chậm trễ trước khi mouseDown được phân phối sẽ không hoạt động vì lý do tôi đang cố gắng chuyển một số thao tác từ mouseUp sang mouseDown là làm cho giao diện người dùng cảm thấy nhạy hơn .. –

Trả lời

8

để trả lời câu hỏi cụ thể về lý do tại sao điều này xảy ra - vào Cocoa chúng ta không xem xét một kéo đã bắt đầu cho đến khi chuột đã di chuyển một vài pixel . Điều này đảm bảo chống lại 'tình cờ' kéo nếu bạn đang cẩu thả với các nhấp chuột. Trên Linux và Win32, bộ công cụ cửa sổ có thể thực hiện phát hiện kéo. Nếu bạn chỉ cần nhấn giữ nút phát hiện thời gian ra và chuột xuống được phân phối. Trên ca cao, chúng tôi không có thời gian ra, đó là lý do tại sao không có gì xảy ra cho đến khi kéo được phát hiện hoặc một con chuột lên xảy ra.

Đó là rất nhiều chi tiết, nhưng kết luận là hành vi không nhất quán và chúng tôi luôn có thể phân phối chuột ngay lập tức mà không cần chờ phát hiện kéo hoàn tất.

Tôi không thấy giải pháp khác vì điều này xảy ra trước khi Kiểm soát thấy sự kiện.

Xem this bug có bản vá lỗi cho win32, gtk và SWT cacao.

+0

Thật tuyệt vời! Một bản vá, cho tất cả các nền tảng không kém, trong vòng một hoặc hai ngày! Ấn tượng! Cảm ơn bạn! –

+0

Dường như MouseDown bị trì hoãn trong khi kéo là cố ý. Đối với những người chơi cùng ở nhà, vui lòng xem lỗi Eclipse nêu trên để biết thêm chi tiết. –

1

Tôi đã phải đối mặt với cùng một vấn đề và tìm thấy giải pháp. Sau khi bạn đính kèm một DragSource vào tiện ích tùy chỉnh của mình, vòng lặp sự kiện sẽ bị chặn trong trình đơn thả xuống của tiện ích đó và sẽ ăn các sự kiện di chuyển chuột để phát hiện một lần kéo. (Tôi đã chỉ nhìn vào mã GTK của SWT để tìm ra điều này, vì vậy nó có thể hoạt động hơi khác trên các nền tảng khác, nhưng giải pháp của tôi hoạt động trên GTK, Win32 và Cocoa.) Trong tình huống của tôi, tôi không quá nhiều quan tâm đến việc phát hiện sự kiện chuột xuống ngay khi nó xảy ra, nhưng tôi quan tâm đến việc giảm đáng kể độ trễ phát hiện kéo, vì toàn bộ mục đích triển khai Canvas của tôi là để người dùng kéo nội dung.Để tắt chặn vòng lặp sự kiện và tính năng phát hiện kéo tích hợp, tất cả những gì bạn phải làm là:

setDragDetect(false); 

Trong mã của tôi, tôi đang làm điều này trước khi đính kèm DragSource. Như bạn đã chỉ ra, điều này sẽ để lại cho bạn vấn đề mà bạn không thể bắt đầu kéo nữa. Nhưng tôi cũng đã tìm ra giải pháp cho điều đó. May mắn thay, sự kiện tạo kéo là thuần Java và không nền tảng cụ thể trong SWT (chỉ phát hiện kéo). Vì vậy, bạn chỉ có thể tạo ra sự kiện DragDetect của riêng bạn tại một thời điểm khi nó thuận tiện cho bạn. Tôi đã đính kèm một MouseMoveListener vào Canvas của tôi, và nó lưu trữ vị trí chuột cuối cùng, khoảng cách kéo tích lũy và có hay không nó đã tạo ra một sự kiện DragDetect (trong số những thứ hữu ích khác). Đây là triển khai mouseMove():

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

Và điều đó sẽ thay thế tính năng phát hiện chặn chặn được tích hợp sẵn cho bạn.