Duplicate :
|
|
Relates :
|
|
Relates :
|
orig synopsis: "several mouse event bugs" Name: ggC50526 Date: 10/01/97 /* The following test program demonstrates some serious bugs in java event management under Windows NT, as well as various inconsistencies between the Solaris and NT platforms. The program creates a frame containing various components and logs all generated mouse events. 1) Unexpected, unbalanced mousePressed events are generated when dragging out of some components. To reproduce: Position the cursor in either the red Button or the green Label. Press the mouse button, drag into the white background, and release. As the cursor leaves the Button or Label an inappropriate mousePressed event is generated. When the mouse button is released a single mouseReleased event is generated, despite there having been two prior mousePressed events. Note that in the case of the Button all three events are from the Button while in the case of the Label the second mousePressed and the mouseReleased come from the background Frame. Workaround: Way too ugly to describe. Comments: This is a very serious problem because it breaks the model of "what goes down must come up". The complexity of event handling gets totally out of hand if it cannot be assumed that every mousePressed will eventually be followed by a mouseReleased from the same source. 2) MouseDragged events don't always come from the component where the drag originated. To reproduce: Position the cursor in the green Label. Press the mouse button and drag into the white background. When the cursor leaves the Label the mouseDragged events stop coming from the Label and begin to come from the background Frame. Workaround: Again, a convoluted workaround is possible, but it's terrible to have to install mouseMotionListeners on components other than the one for which drag operations are to be supported. Comments:on Solaris working We are aware that there are open bug reports on this problem but are mentioning it to stress the importance of getting this fixed. The principle that mouseDragged events (and the subsequent mouseReleased) come from the originating component is very useful for good modular event management but loses much of its value if chewing gum and baling wire have to be used to handle a few broken cases. 3) Spurious mouseClicked events are generated under certain circumstances. To reproduce: Position the cursor in the white background area. Press the mouse button, drag into either the red Button or the green Label, and release. Move the cursor back to the white background. As the cursor leaves the Button or Label an inappropriate mouseClicked event is generated. Workaround: Ignore mouseClicked events not preceded by a mousePressed at the same location. Comments: More ugly platform-specific code... 4) MouseEntered events generated in wrong coordinate system. To reproduce: Move the cursor into and out of various components. MouseEntered events generated when moving to or from the Button or Label components apparently have their locations referenced to the coordinate system of the component just exited. Workaround: Haven't looked for one. Comments: This is obviously broken behavior but isn't a big deal for us since at this point it doesn't affect our application work. It was observed incidentally in the course of investigating the above. The bugs listed above have been replicated on several versions of NT JDK 1.1 and 1.2 (up to 1.2J). They have not been observed in any version of the Solaris JDK. We haven't tried any of this on Win95. All the bugs listed above vary depending on the particular components used. In these cases it's pretty easy to identify which variations are clearly broken. However, there is a more general concern about the inconsistent management of events across platforms and across various components on the same platform. Observe mouseEntered and mouseExited events with this program during moves and drags on NT vs Solaris for several examples. With the exceptions documented above, most of the variations aren't clearly wrong in their own context, but is is absolutely wrong for them to vary so much. Unless and until a uniform set of event distribution rules is specified and enforced across all platforms we'll have to settle for "write once, run anywhere, so long as you don't do anything too fancy". Alan Buchanan GE Medical Systems (HJ licensee) ###@###.### */ import java.awt.*; import java.awt.event.*; public class EventTest { public static void main( String argv[] ) { frame_.setLayout( null ); frame_.setBounds( 99, 99, 350, 150 ); frame_.setBackground( Color.white ); frame_.addMouseListener ( ear_ ); frame_.addMouseMotionListener( ear_ ); addComponent( new Button(), Color.red, 50, 50 ); addComponent( new Label(), Color.green, 150, 50 ); addComponent( new Light(), Color.blue, 250, 50 ); frame_.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit(0); } } ); frame_.setVisible( true ); } private static void addComponent( Component c, Color color, int x, int y ) { c.setBackground( color ); c.setBounds( x, y, 50, 50 ); c.addMouseListener ( ear_ ); c.addMouseMotionListener( ear_ ); frame_.add( c ); } static Frame frame_ = new Frame(); static MouseEar ear_ = new MouseEar(); } // EventTest class Light extends Component { public void paint( Graphics g ) { g.setColor( getBackground() ); g.fillRect( 0, 0, getSize().width, getSize().height ); } } // Light class MouseEar implements MouseListener, MouseMotionListener { public void mousePressed ( MouseEvent e ) { mouseTrap( e, "press" ); } public void mouseReleased( MouseEvent e ) { mouseTrap( e, "release" ); } public void mouseClicked ( MouseEvent e ) { mouseTrap( e, "click" ); } public void mouseEntered ( MouseEvent e ) { mouseTrap( e, "enter" ); } public void mouseExited ( MouseEvent e ) { mouseTrap( e, "exit" ); } public void mouseDragged ( MouseEvent e ) { mouseTrap( e, "drag" ); } public void mouseMoved ( MouseEvent e ) { mouseTrap( e, "move" ); } private void mouseTrap( MouseEvent event, String id ) { if( last_.id_.equals( id ) && last_.event_.getSource() == event.getSource() && ( id.equals( "drag" ) || id.equals( "move" ) ) ) { System.out.print( id.equals( "drag" ) ? "=" : "-" ); last_ = new EventStash( event, id, false ); return; } if( !last_.done_ ) System.out.print( s( last_.event_.getPoint() ) ); Component c = (Component)event.getSource(); String s = c.getClass().getName(); s = s.substring( s.lastIndexOf( "." ) + 1 ) + ( ( c instanceof Frame ) ? "\t" : "@" + s( c.getLocation() ) ); System.out.print( "\n" + id + "\t" + s + "\t" + s( event.getPoint() ) ); last_ = new EventStash( event, id, true ); } private String s( Point p ) { return "" + p.x + "," + p.y; } private EventStash last_ = new EventStash( null, "", true ); } // MouseEar class EventStash { public MouseEvent event_; public String id_; public boolean done_; public EventStash( MouseEvent event, String id, boolean done ) { event_ = event; id_ = id; done_ = done; } } // EventStash company - GE Medical Systems , email - ###@###.### ====================================================================== phil.race@eng 1997-11-06 BUG #1 SPURIOUS MOUSE UPs/DOWNs/CLICKs -------------------------------------- This is points (1) and (3) from the original submitter awt_Toolkit.cpp has a variable m_mouseDown, which is apparently used to track mouse state, to detect missing events For instance if a mouse move event is seen in which a mouse button is DOWN, but no mouse button press event was seen we must have missed the mouse press. If mouse state is not what is expected the code "synthesises" the missing event, ostensibly to ensure that AWT components do not miss events which could cause them to "lock" into the wrong state : such as an AWT button not bring redrawn in the right way for button state. 1) I removed the synthesis code and I haven't seen this problem myself under NT 4.0, unfortunately, I have no idea how this effect was previously reproduced anyway. 2) BUT the logic is flawed, in at least one way. The check on button state is done ONLY if we have just transitioned into an AWT window/component from a different AWT window/component or a non-java window. The logic is as follows:- // Look for mouse transitions between windows & create // MouseExit & MouseEnter messages if (mouseComp != m_lastMouseOver) { .... if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) { if (msg.wParam&(MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) { if (!m_mouseDown && msg.message != WM_LBUTTONDOWN && msg.message != WM_RBUTTONDOWN && msg.message != WM_MBUTTONDOWN && p) { p->SendMessage(WM_LBUTTONDOWN, msg.wParam, msg.lParam); } m_mouseDown = TRUE; } This means + IF the mouse moved to a different window + AND we have a mouse event + AND we don't know the mouse is down + AND some button is pressed + AND this isn't the button press event itself + Then - hey we must have missed it. i.e. we only set m_mouseDown = TRUE on window transitions! Suppose we have a button in a window(frame) If we press the mouse on the window b/g and drag into the button, then the above logic will suppose we missed the event. This is wrong. The button press was detected, but took place on a different component. The 1.1.4 code will generate the mouse down and everything after that is just not worth analysing .. So: My fix is to remove this code entirely unless someone can demonstrate that it serves any useful purpose. Certainly removinf it did no harm I did only limited testing and only under NT4.0 but all the cases I can think of: such as doing the press & release over some other non-java window seem fine. But this is all now moot as this is fixed as a result of the work tou fix bug 4038721. In 1.1.4 we would generate the mouse up/down only if the mouse was over a different component than last time. In 1.1.5 that part of the condition is ignored and we always check button state. This specifically addresses the problem I identified, but speaking to the bug fix implementor, he does not know why the mouse event check is there at all either. ##################### BUG #2 Dragging not working on all components --------------------------------------------- This is point (2) from the original submitter. When the mouse is pressed and you move from a component the mouse should remain associated with it until the button is released This is happening for Buttons, and light weight components For Labels (and may be other stuff?) we see a different behaviour Windows issues the mouse move events to the Label ONLY SO LONG AS the pointer is over the Label, once it leaves the Label to a new component (eg window b/g) , the new component gets the events, even if you re-enter the label. This seems to be because Labels don't automatically "capture" the mouse for you The blue canvas in bugid 4083025 works because awt_Canvas.cpp explictly captures and releases the mouse adding the same code in to Label seems to have the desired effect. There are probably other such cases but I don't know what they are .. BUG #3 Entering a component: mouse position coordinate system ------------------------------------------------------------- This is point (4) from the original submitter There is a bug in the mouse enter position if the mouse is not dragged or otherwise captured on a component when it enters the new component. The bug occurs in AwtToolkit::PreProcessMouseMsg() because the value in mouseLParam is converted to the coordinate space of the component just exited, for synthesising the EXIT event, but then is used in this inappropriate "mode" when synthesising the ENTER event. In the drag case it is recalculated, but in the move case the logic says that since the component on whichthe message was delivered and the mouse component (just entered) are the same, the coordinates don't need transforming. Well .. this was true when you entered the method, but we just overwrote that value! ====================================================================== Name: mc57594 Date: 11/15/99 See #2 above: MouseDragged events don't always come from the component where the drag originated. The following program is visualizing the bug in the console. (It writes the source of the mouseDragged event to the console) ? If you start a dragging operation over the button or the frame (in the center area) the source of the dragging event will be the component where you pressed the mouse button. If you starts it over the label the source of the dragging will be the component currently below the cursor. ? As I recently found the List class also works incorrectly. Maybe this is an other bug, but probably the same, because it produces exactly the same result. You can check this with the test program too. OS: WIN NT 4.0 JDK 1.2.2 ? ///////////// the test code ///////////// ? import java.awt.*; import java.awt.event.*; ? public class test? implements MouseMotionListener { ??? public static void main(String args[]) ??? { ??????? test t=new test(); ??????? Frame frame=new Frame(); ??????? Label l1=new Label("label1"); ??????? List l2=new List(); ??? ??? Button l3 =new Button("button"); ??????? frame.add(l1,"North"); ??????? frame.add(l2,"East"); ??????? frame.add(l3,"West"); ??????? frame.setBounds(0,0,200,200); ??????? frame.addMouseMotionListener(t); ??????? l1.addMouseMotionListener(t); ??????? l2.addMouseMotionListener(t); ??????? l3.addMouseMotionListener(t); ??????? frame.setVisible(true); ??? } ? ??? public void mouseMoved(MouseEvent event) ??? { ??? } ??? public void mouseDragged(MouseEvent event) ??? { ??????? System.out.println("DRAGGING -"+event.getSource()); ??? } } ? (Review ID: 96836) ======================================================================
|