# 矩形涂鸦画板

![](./doodle.png)

编写一个矩形涂鸦画板，实现功能：

* 鼠标左键按下拖动绘制矩形，鼠标左键弹起时完成绘制
* 按`'c'`键清空画板
* 按`'ESC'`键退出

基本框架代码如下：

```python
import numpy as np
import cv2 as cv
from random import randint


class Painter:
    def __init__(self) -> None:
        self.mouse_is_pressed = False
        self.last_pos = (-1, -1)
        self.width = 300
        self.height = 512
        self.img = np.zeros((self.width, self.height, 3), np.uint8)
        self.window_name = 'painter'
        self.color = None

    def run(self):
        print('画板，拖动鼠标绘制矩形框，按ESC退出，按c键清空画板')
        cv.namedWindow(self.window_name)
        cv.setMouseCallback(
            self.window_name,
            lambda event, x, y, flags, param: self.on_draw(
                event, x, y, flags, param
            )
        )
        while True:
            cv.imshow(self.window_name, self.img)
            k = cv.waitKey(1) & 0xFF
            if k == ord('c'):
                self.clean()
            elif k == 27:
                break

        cv.destroyAllWindows()

    def on_draw(self, event, x, y, flags, param):
        # TODO(You): 请正确实现画板事件响应，完成功能

    def clean(self):
        cv.rectangle(self.img, (0, 0), (self.height, self.width), (0, 0, 0), -1)

    def begin_draw_rectangle(self, pos1, pos2):
        if self.color is None:
            self.color = (randint(0, 256), randint(0, 256), randint(0, 256))
        cv.rectangle(self.img, pos1, pos2, self.color, -1)

    def end_draw_rectangle(self, pos1, pos2):
        self.color = None


if __name__ == '__main__':
    p = Painter()
    p.run()
```

以下正确实现鼠标事件，完成画板绘制逻辑的代码是？

## 答案

```python
pos = (x, y)
if event == cv.EVENT_LBUTTONDOWN:
    self.mouse_is_pressed = True
    self.last_pos = pos
elif event == cv.EVENT_MOUSEMOVE:
    if self.mouse_is_pressed == True:
        self.begin_draw_rectangle(self.last_pos, pos)
elif event == cv.EVENT_LBUTTONUP:
    self.end_draw_rectangle(self.last_pos, pos)
    self.mouse_is_pressed = False
```

## 选项

### 鼠标移动事件里缺乏判断

```python
pos = (x, y)
if event == cv.EVENT_LBUTTONDOWN:
    self.mouse_is_pressed = True
    self.last_pos = pos
elif event == cv.EVENT_MOUSEMOVE:
    self.begin_draw_rectangle(self.last_pos, pos)
elif event == cv.EVENT_LBUTTONUP:
    self.end_draw_rectangle(self.last_pos, pos)
    self.mouse_is_pressed = False
```

### 鼠标按下事件里缺乏标记

```python
pos = (x, y)
if event == cv.EVENT_LBUTTONDOWN:
    self.last_pos = pos
elif event == cv.EVENT_MOUSEMOVE:
    if self.mouse_is_pressed == True:
        self.begin_draw_rectangle(self.last_pos, pos)
elif event == cv.EVENT_LBUTTONUP:
    self.end_draw_rectangle(self.last_pos, pos)
    self.mouse_is_pressed = False
```

### 鼠标按起时忘记清空标记

```python
pos = (x, y)
if event == cv.EVENT_LBUTTONDOWN:
    self.mouse_is_pressed = True
    self.last_pos = pos
elif event == cv.EVENT_MOUSEMOVE:
    if self.mouse_is_pressed == True:
        self.begin_draw_rectangle(self.last_pos, pos)
elif event == cv.EVENT_LBUTTONUP:
    self.end_draw_rectangle(self.last_pos, pos)
```
