QwtPicker State Machine¶
In a graphical interaction system, a user action is often a sequence of events rather than a single instant. For example:
- Drag operation: Press mouse -> Move mouse -> Release mouse
- Rectangle selection: Click first point -> Move mouse -> Click second point
- Polygon drawing: Click multiple points -> Right-click to finish
Without a state machine, event handlers would need many if-else branches and state variables, which is hard to maintain.
Qwt's QwtPicker uses a state machine to manage the interaction process. The corresponding implementation is located in the qwt_picker_machine.h/cpp files.
Advantages of the QwtPicker State Machine¶
The state machine separates event-sequence processing from the actual operation:
- The state machine is responsible for recognizing complete event sequences
QwtPickeris responsible for executing specific drawing, selection, and other operations
All QwtPicker state machines inherit from QwtPickerMachine and provide a unified transition() interface. QwtPicker does not need to know which specific interaction mode is in use.
Adding a new interaction mode only requires inheriting from QwtPickerMachine and implementing the state transition logic, without modifying QwtPicker core code.
State transitions during the interaction process are managed automatically, avoiding errors caused by manually maintaining state variables.
How the QwtPicker State Machine Works¶
The QwtPicker state machine mechanism combines an observer pattern with a state pattern:
1 | |
QwtPicker acts as an event filter installed on the parent widget. It receives events from the parent window, dispatches them to the corresponding widgetXXXEvent methods, and invokes the state machine for transitions.
Specific drawing actions are abstracted by QwtPicker into the following states:
| State | Description |
|---|---|
| begin() | Start selection |
| append() | Add point |
| move() | Move point |
| remove() | Remove point |
| end() | End selection |
The specific operations that compose moving, removing, and adding points are managed by the state machine. For example: clicking a point, moving the mouse, releasing the mouse, and ending the selection. This way, QwtPicker handles mouse and keyboard events without also tracking state transitions.
The core of the state machine processing is the transition method. The widgetXXXEvent methods in QwtPicker all call the transition method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
This transition() method receives an event and returns a command sequence in commandList. Each state machine instance inherits from QwtPickerMachine and implements transition() to produce that sequence.
The following flowchart shows the path:
flowchart TD
A[User Interaction Event<br>Mouse/Keyboard Event] --> B{QwtPicker Event Filter}
B --> C[Dispatch Event to Corresponding Method]
C --> D{widgetMousePressEvent etc.}
D --> E[Call transition Method]
E --> F{QwtPickerMachine<br>State Manager}
subgraph F [State Machine Internal Processing]
F1[Receive Event] --> F2[Match Event Pattern]
F2 --> F3[State Transition Logic]
F3 --> F4[Generate Command Sequence]
F4 --> F5[Update Internal State]
end
F --> G[Return Command Sequence<br>Begin/Append/Move/Remove/End]
G --> H[QwtPicker Executes Commands]
subgraph H [Command Executor]
H1[begin] --> H2[append]
H2 --> H3[move]
H3 --> H4[remove]
H4 --> H5[end]
end
H --> I[Specific Business Logic]
subgraph I [QwtPicker Business Processing]
I1[Update pickedPoints Array]
I2[Show/Hide Rubber Band]
I3[Update Tracker Display]
I4[Emit Corresponding Signals]
end
I --> J[State Feedback]
J --> F
style F fill:#e1f5fe
style H fill:#f3e5f5
style I fill:#e8f5e8
Taking QwtPickerDragPointMachine as an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
The sequence diagram for a mouse drag looks like this:
sequenceDiagram
participant User as User
participant System as Event System
participant Picker as QwtPicker
participant Machine as State Machine (DragPointMachine)
participant Actions as QwtPicker Actions
Note over User,Actions: t0: Mouse press time
User->>System: Mouse press
System->>Picker: widgetMousePressEvent()
Picker->>Machine: transition(mouse press event)
Note right of Machine: State 0 -> State 1
Machine-->>Picker: [Begin, Append]
Picker->>Actions: begin()
Picker->>Actions: append(pos)
Note over Actions: Activate picker<br>Add first point
Note over User,Actions: t1-t3: Mouse move process
loop Each mouse move
User->>System: Mouse move
System->>Picker: widgetMouseMoveEvent()
Picker->>Machine: transition(mouse move event)
Note right of Machine: Stay in State 1
Machine-->>Picker: [Move]
Picker->>Actions: move(pos)
Note over Actions: Update last point position<br>Redraw rubber band in real-time
end
Note over User,Actions: t4: Mouse release time
User->>System: Mouse release
System->>Picker: widgetMouseReleaseEvent()
Picker->>Machine: transition(mouse release event)
Note right of Machine: State 1 -> State 0
Machine-->>Picker: [End]
Picker->>Actions: end()
Note over Actions: End selection<br>Validate and emit selected signal
In QwtPickerMachine, the parameter of the setState() function represents the internal state of the state machine. These state values are defined and maintained by each state machine individually and have no unified meaning. Different state machines use different state values to represent their specific interaction phases.
For example, QwtPickerDragPointMachine has state values 0 and 1, representing the initial state and drag state respectively.
State transitions can be described using a state transition diagram. The state transition diagram for QwtPickerDragPointMachine is as follows:
stateDiagram-v2
[*] --> State0: Initialization complete
State0 --> State1: Mouse press -> Begin + Append
State1 --> State1: Mouse move -> Move
State1 --> State0: Mouse release -> End
The state machine turns event types into plot operations.
Complex interaction logic is decomposed into:
- Event recognition (state machine)
- Command execution (QwtPicker)
- Drawing (rubber band, tracker)
graph TB
A[Event Types] --> B{State Machine Processing}
subgraph A [Input Event Types]
A1[QEvent::MouseButtonPress]
A2[QEvent::MouseButtonRelease]
A3[QEvent::MouseMove]
A4[QEvent::KeyPress]
A5[QEvent::KeyRelease]
A6[QEvent::Wheel]
A7[QEvent::Enter]
A8[QEvent::Leave]
end
B --> C[DragPointMachine]
B --> D[ClickPointMachine]
B --> E[DragRectMachine]
B --> F[TrackerMachine]
subgraph C [Drag Point Selection State Machine]
C1[Press: Begin + Append<br>Enter State 1]
C2[Move: Move<br>Stay in State 1]
C3[Release: End<br>Return to State 0]
C4[Key: Toggle State]
end
subgraph D [Click Point Selection State Machine]
D1[Press: Begin + Append + End<br>Single-step completion]
D2[Move: No action]
D3[Release: No action]
end
subgraph E [Drag Rectangle Selection State Machine]
E1[Press: Begin + Append + Append<br>Enter State 2]
E2[Move: Move<br>Stay in State 2]
E3[Release: End<br>Return to State 0]
end
subgraph F [Tracker State Machine]
F1[Enter: Begin + Append<br>Enter State 1]
F2[Move: Move<br>Stay in State 1]
F3[Leave: Remove + End<br>Return to State 0]
end
style A fill:#f5f5f5
style C fill:#e8f5e8
style D fill:#e3f2fd
style E fill:#fff3e0
style F fill:#f3e5f5
Built-in QwtPicker State Machines¶
1. QwtPickerTrackerMachine (Tracker State Machine)¶
Purpose¶
Real-time tracking of mouse position with information display, without performing any selection operations.
State Transition Process¶
The list below enumerates, for each QEvent type, the command sequence produced by QwtPickerTrackerMachine::transition() and the resulting state: entering the widget or moving the mouse emits Begin + Append, subsequent moves emit Move, and leaving the widget emits Remove + End:
1 2 3 4 | |
State Transition Diagram¶
The state transition diagram below visualizes the same logic; the meaning of each state (State 0 = not tracking, State 1 = tracking) is defined by QwtPickerTrackerMachine itself via the setState() calls inside its transition() implementation:
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State1: Enter/Move -> Begin + Append
State1 --> State1: Move -> Move
State1 --> State0: Leave -> Remove + End
Use Cases¶
- Coordinate display
- Mouse hover tooltips
- Real-time value display
- Position feedback for measurement tools
2. QwtPickerClickPointMachine (Click Point Selection State Machine)¶
Purpose¶
Select a point through a single click.
State Transition Process¶
QwtPickerClickPointMachine::transition() completes a selection in one step: a press matching MouseSelect1, or a key matching KeySelect1, emits Begin, Append, and End at once and leaves the machine in State 0 — there is no intermediate state:
1 2 3 | |
State Transition Diagram¶
The diagram below shows this one-shot machine as a self-loop on State 0; the state values are those maintained by QwtPickerClickPointMachine through its internal setState() calls:
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State0: Mouse press/Key press -> Begin + Append + End
Use Cases¶
- Selecting data points
- Marking specific positions
- Simple coordinate selection
- Quick positioning operations
3. QwtPickerDragPointMachine (Drag Point Selection State Machine)¶
Purpose¶
Precisely select a point position through drag operations.
State Transition Process¶
QwtPickerDragPointMachine::transition() starts the drag on a MouseSelect1 press (Begin + Append, entering State 1), tracks mouse moves and wheel events with Move, and finishes on release with End; a KeySelect1 key press toggles between State 0 and State 1 for keyboard operation:
1 2 3 4 5 6 | |
State Transition Diagram¶
The state transition diagram below summarizes these rules; State 0 (idle) and State 1 (dragging) are the values QwtPickerDragPointMachine assigns via setState() in its transition() implementation:
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State1: Mouse press -> Begin + Append
State1 --> State1: Mouse move/Wheel -> Move
State1 --> State0: Mouse release -> End
State0 --> State1: Key press -> Begin + Append
State1 --> State0: Key press -> End
Use Cases¶
- Precise position selection (e.g., real-time Panner)
- Point selection requiring fine adjustment
- Drag positioning tools
- High-precision measurement
4. QwtPickerClickRectMachine (Click Rectangle Selection State Machine)¶
Purpose¶
Define a rectangular area through two clicks.
State Transition Process¶
QwtPickerClickRectMachine::transition() spans three states: the first press emits Begin + Append (State 1), the first release appends the opposite corner (State 2), and only the next press emits End and returns to State 0 — the rectangle is thus fixed by two separate clicks:
1 2 3 4 5 6 | |
State Transition Diagram¶
The diagram below shows this two-click sequence; State 0/1/2 are exactly the values maintained by QwtPickerClickRectMachine via setState(), marking idle, first corner placed, and rectangle awaiting confirmation:
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State1: First press -> Begin + Append
State1 --> State1: Move -> Move
State1 --> State2: First release -> Append
State2 --> State0: Second press -> End
Use Cases¶
- Precise rectangular area selection
- Zoom area requiring precise positioning
- Coordinate-aligned rectangle drawing
- Architectural drawing measurement
5. QwtPickerDragRectMachine (Drag Rectangle Selection State Machine)¶
Purpose¶
Quickly select a rectangular area through drag operations.
State Transition Process¶
QwtPickerDragRectMachine::transition() emits Begin + Append + Append on the initial MouseSelect1 press and jumps directly to State 2, where mouse moves produce Move (resizing the rubber-band rectangle) and the release produces End; KeySelect1 toggles between State 0 and State 2:
1 2 3 4 5 | |
State Transition Diagram¶
The diagram below contrasts with the click-rectangle machine by skipping State 1 entirely; the state values are those QwtPickerDragRectMachine assigns through setState() — State 0 (idle) and State 2 (dragging a live rectangle):
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State2: Mouse press -> Begin + Append + Append
State2 --> State2: Mouse move -> Move
State2 --> State0: Mouse release -> End
State0 --> State2: Key press -> Begin + Append + Append
State2 --> State0: Key press -> End
Use Cases¶
- Quick rectangular area selection
- Interactive zoom
- Area screenshot tools
- Batch selection operations
6. QwtPickerDragLineMachine (Drag Line Selection State Machine)¶
Purpose¶
Select a line segment through drag operations.
State Transition Process¶
QwtPickerDragLineMachine::transition() works like the drag-rectangle machine but selects a line segment: the initial press emits Begin + Append + Append (start and end points) and enters State 1, moves update the end point with Move, and the release emits End; KeySelect1 toggles State 0/1:
1 2 3 4 5 | |
State Transition Diagram¶
The state transition diagram below shows this two-point drag; State 0 and State 1 are defined by QwtPickerDragLineMachine's own setState() calls — idle versus dragging the line's end point:
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State1: Mouse press -> Begin + Append + Append
State1 --> State1: Mouse move -> Move
State1 --> State0: Mouse release -> End
State0 --> State1: Key press -> Begin + Append + Append
State1 --> State0: Key press -> End
Use Cases¶
- Distance measurement tools
- Line segment drawing
- Direction indicators
- Angle measurement
7. QwtPickerPolygonMachine (Polygon Selection State Machine)¶
Purpose¶
Create a polygon area through multiple clicks.
State Transition Process¶
QwtPickerPolygonMachine::transition() collects vertices one by one: the first MouseSelect1 press emits Begin + Append + Append (State 1), each later press adds a vertex with Append, moves preview the current edge with Move, and a press matching MouseSelect2 closes the polygon with End:
1 2 3 4 5 6 | |
State Transition Diagram¶
The diagram below shows the vertex-accumulation loop in State 1 and its exit via the second mouse button; the states are those maintained by QwtPickerPolygonMachine through its setState() calls:
stateDiagram-v2
[*] --> State0: Initialization
State0 --> State1: First press -> Begin + Append + Append
State1 --> State1: Subsequent press -> Append
State1 --> State1: Move -> Move
State1 --> State0: Right-click/Second button -> End
Use Cases¶
- Complex area selection
- Polygon drawing tools
- Custom shape annotations
- Geographic information system area selection
Summary¶
All built-in state machines map events to the same five commands (begin, append, move, remove and end), and each defines its own state values. To add an interaction mode, inherit from QwtPickerMachine and implement transition(); QwtPicker itself does not need to change.