The problem

When you drag an object with the mouse, you want the object to maintain its position with respect to the mouse cursor as you move it. Some programs fail to "anchor" the object to the mouse, and they "lose" the object when the mouse moves to troublesome positions.

Discussion

When you first press a mouse button on an object to start dragging it, that point becomes an anchor on the object. Constraints imposed by the program should not affect the anchor point. For example, if the program does not let you drag the object past some border, then the object should maintain its anchor when you move the mouse back.

Here are two example programs that implement dragging. Both let you drag a rectangle inside a window, and make sure that the rectangle cannot be moved past the window's bounds.

  • drag-incorrect.py - incorrect version. This one updates the position of the rectangle based on the deltas between successive positions of the mouse. When you move the mouse past the edge of the window and then move it back inside, the anchor point for the object gets changed --- the rectangle "slides away" from its original position with respect to the mouse.

  • drag-correct.py - correct version. This one remembers the anchor point as soon as you press the mouse button, in the form of offsets to the rectangle's starting position. On each mouse motion, it computes a new positio n for the rectangle based on the anchor's offsets. Keeping the anchor offsets from the beginning is the key to maintaining a stable position.

Summary

To implement dragging with the mouse, make sure the dragged object maintains a constant offset from the mouse cursor. When the mouse moves, recompute the object's new position based on this offset.

on_button_press (event):
    drag_offset = event.position - dragged_object.position
    turn on the "dragging" flag

on_mouse_move (event):
    dragged_object.position = event.position - drag_offset
    apply any suitable constraints to the object's position
    repaint

on_button_release (event);
    turn off the "dragging" flag

Attic/User Interface Patterns/Dragging Objects (last edited 2013-11-23 01:17:47 by WilliamJonMcCann)