-
Notifications
You must be signed in to change notification settings - Fork 0
/
T_Test4.py
210 lines (166 loc) · 6.43 KB
/
T_Test4.py
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# -*- encoding: utf-8 -*-
# Python 3.9.6 64bit
'''
@File : MySktech.py
@Time : 2022/01/03 21:51
@Author : Wreng
@Description : wxpython 实现简易的画板
@Other : version - Python 3.9.6 64bit, wxPython 4.1.1
'''
import wx
"""
实现画板,有两种方式:直接法和缓冲法。
缓冲法,可以有效的避免屏闪;当绘图不是很复杂的时候,直接法的屏闪也不是很明显。
两种的实现也比较简单,分别由专门的dc一一对应的。
"""
BUFFERED = True # 使用缓冲法,即 double buffered
# BUFFERED = False # 使用直接法
class Myline():
"""笔画类,包含笔迹的颜色、粗细、样式、数据点"""
def __init__(self, color, thick, style, datas):
self.pen_msg = (color, thick, style)
self.datas = datas
class SimpleSketchWindow(wx.Window):
"""画板缓冲窗口"""
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
self.cur_pos = (0,0) # 当前鼠标位置
self.cur_line = [] # 当前笔画 [(x1, y1), (x2, y2), ... ,(xn,yn)]
self.lines = [] # 所有笔画 [line1, line2, ..., line m]
self.pen_color = 'RED' # 笔迹颜色
self.pen_thick = 4 # 笔迹粗细
self.pen_style = wx.PENSTYLE_SOLID # 笔类型
# 设置缓存区
if BUFFERED:
self.buffer = None
self.InitBuffer()
# 设置背景颜色
self.SetBackgroundColour('white')
# 设置鼠标图标为“铅笔”
self.SetCursor(wx.Cursor(wx.CURSOR_PENCIL))
# 绑定事件
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_PAINT, self.OnPaint) # 触发时机:窗口大小变换
self.Bind(wx.EVT_SIZE, self.OnSize)
def InitBuffer(self):
"""初始化缓冲区"""
if BUFFERED:
# 设置缓冲区与窗口的大小一致
size = self.GetClientSize()
self.buffer = wx.Bitmap(*size)
# 第一个参数为None,相当于初始化 buffer
dc = wx.BufferedDC(None, self.buffer)
else:
# 直接获得当前窗口的设别上下文
dc = wx.ClientDC(self)
# 默认的绘画:绘制已存在的笔迹
self.DefaultDrawing(dc)
# 添加你的绘画
self.DoMyDrawing(dc)
def DefaultDrawing(self, dc:wx.DC):
"""默认绘画"""
# 设置背景颜色
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear() # 使用当前背景刷来清除设备上下文。
# 绘制所有的笔画
self.DrawAllLines(dc)
def DrawAllLines(self, dc:wx.DC):
"""绘制所有的直线"""
for line in self.lines:
# 设置笔画
pen = wx.Pen(*line.pen_msg)
dc.SetPen(pen)
# 绘制直线
for i in range(1, len(line.datas)):
coord = (line.datas[i-1].x, line.datas[i-1].y,
line.datas[i].x, line.datas[i].y)
dc.DrawLine(*coord)
def DoMyDrawing(self, dc:wx.DC):
"""需要继承此类,然后重构此函数"""
pass
# ====================================================================
# 事件响应函数
# ====================================================================
def OnSize(self, event):
"""响应窗口大小改变"""
# 每次窗口大小变换,都需要重新设置缓冲区大小
self.InitBuffer()
print("OnSize")
event.Skip()
def OnPaint(self, event):
"""响应Paint Event"""
if BUFFERED:
wx.BufferedPaintDC(self, self.buffer)
else:
dc = wx.PaintDC(self)
# 重新绘制
self.DefaultDrawing(dc)
self.DoMyDrawing(dc)
print("OnPaint")
event.Skip()
def OnLeftDown(self, event:wx.MouseEvent):
"""鼠标左键按下,记录起始坐标"""
# 获得当前鼠标位置
self.cur_pos = event.GetPosition()
# 新笔画的起点
self.cur_line = []
self.cur_line.append(self.cur_pos)
print("Left Down: (%d, %d)" % (self.cur_pos.x, self.cur_pos.y))
event.Skip()
def OnLeftUp(self, event:wx.MouseEvent):
"""鼠标左键松开,记录当前笔画"""
if len(self.cur_line) > 1:
self.lines.append(Myline(
self.pen_color, self.pen_thick, self.pen_style, self.cur_line))
print("Left Up: (%d, %d)" % (self.cur_pos.x, self.cur_pos.y))
event.Skip()
def OnMotion(self, event:wx.MouseEvent):
"""鼠标移动(左键拖动)"""
if event.Dragging() and event.LeftIsDown():
# 更新鼠标的坐标
pre_pos = self.cur_pos
self.cur_pos = event.GetPosition()
self.cur_line.append(self.cur_pos)
# 设置缓冲区
if BUFFERED:
# 设置缓冲区,当dc销毁时,将 buffer 复制到当前窗口上
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
else:
# 直接获得当前窗口的设别上下文
dc = wx.ClientDC(self)
# 绘制直线
pen = wx.Pen(self.pen_color, self.pen_thick, self.pen_style)
dc.SetPen(pen)
coord = (pre_pos.x, pre_pos.y, self.cur_pos.x, self.cur_pos.y)
dc.DrawLine(*coord)
print("Drawing:", coord)
event.Skip()
class SketchWindow(SimpleSketchWindow):
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
def DoMyDrawing(self, dc: wx.DC):
"""绘制自定义内容"""
self.DrawLogo(dc)
def DrawLogo(self, dc:wx.DC):
"""绘制logo"""
dc.SetPen(wx.Pen('RED'))
dc.DrawRectangle(5, 5, 50, 50)
dc.SetBrush(wx.Brush("MEDIUM SEA GREEN"))
dc.SetPen(wx.Pen('BLUE', 4))
dc.DrawRectangle(15, 15, 50, 50)
class SketchFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, id=-1,
title="简易的画板",
size=(800,600)
)
self.sketch = SketchWindow(parent=self, id=-1)
# 窗口居中
self.Center()
if __name__ == '__main__':
app = wx.App()
frm = SketchFrame()
frm.Show()
app.MainLoop()