激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - 使用Python編寫簡單的畫圖板程序的示例教程

使用Python編寫簡單的畫圖板程序的示例教程

2020-08-04 11:06xishui Python

這篇文章主要介紹了使用Python編寫簡單的畫圖板軟件的示例教程,利用到了經常被用來做游戲的pygame模塊,需要的朋友可以參考下

從這次開始,我會由簡單到困難(其實也不會困難到哪里去)講幾個例程,每一個例程都是我自己寫(或者修改,那樣的話我會提供原始出處)的,都具有一定的操作性和娛樂性。例程中匯盡量覆蓋到以前所講的pygame中方方面面,如果看到哪一步不明白,那就再回去復習復習,基本沒有人會看一遍什么都記住什么都掌握的,重復是學習之母,實踐是掌握一門技藝的最好手段!

這次就先從一個最簡單的程序開始,說實話有些太簡單我都不好意思拿出手了,不過從簡單的開始,容易建立自信培養興趣。興趣是學習之母嘛。我們這次做一個畫板,類似Windows里自帶的畫板,還記不記得第一次接觸電腦用畫板時的驚嘆?現在想起來其實那個真的非常簡陋,不過我們的比那個還要樸素,因為打算一篇講完,就不追加很多功能了,等你把這一次講解的都理解了,很容易可以自己給它增加新的機能。沒準,你就開發出一個非常牛X的畫圖工具擊敗了Photoshop,然后日進斗金名垂千古(眾:喂,別做夢了!)……

功能樣式

做之前總要有個數,我們的程序做出來會是個什么樣子。所謂從頂到底或者從底到頂啥的,咱就不研究了,這個小程序隨你怎么弄了,而且我們主要是來熟悉pygame,高級的軟件設計方法一概不談~

因為是抄襲畫圖板,也就是鼠標按住了能在上面涂涂畫畫就是了,選區、放大鏡、滴管功能啥的就統統不要了。畫筆的話,基本的鉛筆畫筆總是要的,也可以考慮加一個刷子畫筆,這樣有一點變化;然后顏色應該是要的,否則太過單調了,不過調色板啥的就暫時免了,提供幾個候選色就好了;然后橡皮……橡皮不就是白色的畫筆么?免了免了!還有啥?似乎夠了。。。 OK,開始吧!

框架

pygame程序的框架都是差不多的,考慮到我們這個程序的實際作用,大概建立這樣的一個代碼架子就可以了。

?
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
import pygame
from pygame.locals import *
 
class Brush():
 def __init__(self):
  pass
 
class Painter():
 def __init__(self):
  self.screen = pygame.display.set_mode((800, 600))
  pygame.display.set_caption("Painter")
  self.clock = pygame.time.Clock()
 
 def run(self):
  self.screen.fill((255, 255, 255))
  while True:
   # max fps limit
   self.clock.tick(30)
   for event in pygame.event.get():
    if event.type == QUIT:
     return
    elif event.type == KEYDOWN:
     pass
    elif event.type == MOUSEBUTTONDOWN:
     pass
    elif event.type == MOUSEMOTION:
     pass
    elif event.type == MOUSEBUTTONUP:
     pass
 
   pygame.display.update()
 
if __name__ == '__main__':
 app = Painter()
 app.run()
 
import pygame
from pygame.locals import *
 
class Brush():
 def __init__(self):
  pass
 
class Painter():
 def __init__(self):
  self.screen = pygame.display.set_mode((800, 600))
  pygame.display.set_caption("Painter")
  self.clock = pygame.time.Clock()
 
 def run(self):
  self.screen.fill((255, 255, 255))
  while True:
   # max fps limit
   self.clock.tick(30)
   for event in pygame.event.get():
    if event.type == QUIT:
     return
    elif event.type == KEYDOWN:
     pass
    elif event.type == MOUSEBUTTONDOWN:
     pass
    elif event.type == MOUSEMOTION:
     pass
    elif event.type == MOUSEBUTTONUP:
     pass
 
   pygame.display.update()
 
if __name__ == '__main__':
 app = Painter()
 app.run()

這個非常簡單,準備好畫板類,畫筆類,暫時還都是空的,其實也就是做了一些pygame的初始化工作。如果這樣還不能讀懂的話,您需要把前面22篇從頭再看看,有幾句話不懂就看幾遍:)

這里只有一點要注意一下,我們把幀率控制在了30,沒有人希望在畫畫的時候,CPU風扇狂轉的。而且只是畫板,沒有自動運動的物體,純粹的交互驅動,我們也不需要很高的刷新率。

第一次的繪圖代碼

按住鼠標然后在上面移動就畫東西,我們很容易可以想到這個流程:


按下左鍵  →  繪制flag開
移動鼠標  →  flag開的時候,在移動坐標上留下痕跡
放開左鍵  →  繪制flag關

按下左鍵  →  繪制flag開
移動鼠標  →  flag開的時候,在移動坐標上留下痕跡
放開左鍵  →  繪制flag關
立刻試一試吧:

?
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
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
 
 def start_draw(self):
  self.drawing = True
 def end_draw(self):
  self.drawing = False
 
 def draw(self, pos):
  if self.drawing:
   pygame.draw.circle(self.screen, self.color, pos, self.size)
 
class Painter():
 def __init__(self):
  #*#*#*#*#
  self.brush = Brush(self.screen)
 
 def run(self):
   #*#*#*#*#
    elif event.type == KEYDOWN:
     # press esc to clear screen
     if event.key == K_ESCAPE:
      self.screen.fill((255, 255, 255))
    elif event.type == MOUSEBUTTONDOWN:
     self.brush.start_draw()
    elif event.type == MOUSEMOTION:
     self.brush.draw(event.pos)
    elif event.type == MOUSEBUTTONUP:
     self.brush.end_draw()
 
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
 
 def start_draw(self):
  self.drawing = True
 def end_draw(self):
  self.drawing = False
 
 def draw(self, pos):
  if self.drawing:
   pygame.draw.circle(self.screen, self.color, pos, self.size)
 
class Painter():
 def __init__(self):
  #*#*#*#*#
  self.brush = Brush(self.screen)
 
 def run(self):
   #*#*#*#*#
    elif event.type == KEYDOWN:
     # press esc to clear screen
     if event.key == K_ESCAPE:
      self.screen.fill((255, 255, 255))
    elif event.type == MOUSEBUTTONDOWN:
     self.brush.start_draw()
    elif event.type == MOUSEMOTION:
     self.brush.draw(event.pos)
    elif event.type == MOUSEBUTTONUP:
     self.brush.end_draw()

框架中有的代碼我就不貼了,用#*#*#*#*#代替,最后會給出完整代碼的。

這里主要是給Brush類增加了一些功能,也就是上面我們提到的流程想對應的功能。留下痕跡,我們是使用了在坐標上畫圓的方法,這也是最容易想到的方法。這樣的效果好不好呢?我們試一試:

使用Python編寫簡單的畫圖板程序的示例教程

哦,太糟糕了,再劣質的鉛筆也不會留下這樣斷斷續續的筆跡。上面是當我們鼠標移動的快一些的時候,點之間的間距很大;下面是移動慢一些的時候,勉勉強強顯得比較連續。從這里我們也可以看到pygame事件響應的頻度(這個距離和上面設置的最大幀率有關)。

怎么辦?要修改幀率讓pygame平滑的反應么?不,那樣做得不償失,換一個角度思考,如果有間隙,我們讓pygame把這個間隙連接起來不好么?

第二次的繪圖代碼

思路還是很簡單,當移動的時候,Brush在上一次和這一次的點之間連一條線就好了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
  self.last_pos = None  # <--
 
 def start_draw(self, pos):
  self.drawing = True
  self.last_pos = pos # <--
 def end_draw(self):
  self.drawing = False
 
 def draw(self, pos):
  if self.drawing:
   pygame.draw.line(self.screen, self.color,
     self.last_pos, pos, self.size * 2)
   self.last_pos = pos

使用Python編寫簡單的畫圖板程序的示例教程

在__init__和start_draw中各加了一句,用來存儲上一個點的位置,然后draw也由剛剛的話圓變成畫線,效果如何?我們來試試。嗯,好多了,如果你動作能溫柔一些的話,線條已經很圓潤了,至少沒有斷斷續續的存在了。

滿足了么?我希望你的回答是“NO”,為什么,如果你劃線很快的話,你就能明顯看出棱角來,就好像左圖上半部分,還是能看出是由幾個線段組合的。只有永不滿足,我們才能不停進步。

不過對我們這個例程而言,差不多了,一般人在真正畫東西的時候,也不會動那么快的:)

那么這個就是我們最終的繪圖機制了么?回頭看看我們的樣式,好用還需要加一個筆刷……所謂筆刷,不僅僅是很粗,而且是由很多細小的毛組成,畫出來的線是給人一種一縷一縷的感覺,用這個方法可以實現么?好像非常非常的困難。。。孜孜不倦的我們再次進入了沉思……

這個時候,如果沒有頭緒,就得借鑒一下前輩的經驗了。看看人家是如何實現的?

使用Python編寫簡單的畫圖板程序的示例教程

如果你的Photoshop不錯,應該知道它里面復雜的筆刷設定,而Photoshop畫出來的筆畫,并不是真正一直線的,而是由無數細小的點組成的,這些點之間的間距是如此的密,以至于我們誤會它是一直線……所以說,我們還得回到第一種方法上,把它發揚光大一下~ 這沒有什么不好意思的,放棄第二種方法并不意味著我們是多么的愚蠢,而是說明我們從自己身上又學到了很多!

(公元前1800年)醫生:來,試試吃點兒這種草根,感謝偉大的部落守護神賜與我們神藥!
(公元900年)醫生:別再吃那種草根,簡直是野蠻不開化不尊重上帝,這是一篇祈禱詞,每天虔誠地向上帝祈禱一次,不久就會治愈你的疾病。
(公元1650年)醫生:祈禱?!封建迷信!!!來,只要喝下這種藥水,什么病都能治好!
(公元1960年)醫生:什么藥水?早就不用了!別喝那騙人的”萬靈藥”,還是這種藥片的療效快!
(公元1995年)醫生:哪個庸醫給你開的處方?那種藥片吃半瓶也抵不上這一粒,來來來,試試科技新成果—抗生素
(公元2003年)醫生:據最新科學研究,抗生素副作用太強,畢竟是人造的東西呀……來,試試吃點兒這種草根!早在公元前1800年,文獻就有記載了。
返璞歸真,大抵如此了。

第三次的繪圖代碼

這次我們考慮的更多,希望在點與點之間充滿我們的筆畫,很自然的我們就需要一個循環來做這樣的事情。我們的筆畫有兩種,普通的實心和刷子,實心的話,用circle來畫也不失為一個好主意;刷子的話,我們可能需要一個刷子的圖案來填充了。

下面是我們新的Brush類:

?
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
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
  self.last_pos = None
  self.space = 1
  # if style is True, normal solid brush
  # if style is False, png brush
  self.style = False
  # load brush style png
  self.brush = pygame.image.load("brush.png").convert_alpha()
  # set the current brush depends on size
  self.brush_now = self.brush.subsurface((0,0), (1, 1))
 
 def start_draw(self, pos):
  self.drawing = True
  self.last_pos = pos
 def end_draw(self):
  self.drawing = False
 
 def set_brush_style(self, style):
  print "* set brush style to", style
  self.style = style
 def get_brush_style(self):
  return self.style
 
 def set_size(self, size):
  if size < 0.5: size = 0.5
  elif size > 50: size = 50
  print "* set brush size to", size
  self.size = size
  self.brush_now = self.brush.subsurface((0,0), (size*2, size*2))
 def get_size(self):
  return self.size
 
 def draw(self, pos):
  if self.drawing:
   for p in self._get_points(pos):
    # draw eveypoint between them
    if self.style == False:
     pygame.draw.circle(self.screen,
       self.color, p, self.size)
    else:
     self.screen.blit(self.brush_now, p)
 
   self.last_pos = pos
 
 def _get_points(self, pos):
  """ Get all points between last_point ~ now_point. """
  points = [ (self.last_pos[0], self.last_pos[1]) ]
  len_x = pos[0] - self.last_pos[0]
  len_y = pos[1] - self.last_pos[1]
  length = math.sqrt(len_x ** 2 + len_y ** 2)
  step_x = len_x / length
  step_y = len_y / length
  for i in xrange(int(length)):
   points.append(
     (points[-1][0] + step_x, points[-1][1] + step_y))
  points = map(lambda x:(int(0.5+x[0]), int(0.5+x[1])), points)
  # return light-weight, uniq list
  return list(set(points))
 
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
  self.last_pos = None
  self.space = 1
  # if style is True, normal solid brush
  # if style is False, png brush
  self.style = False
  # load brush style png
  self.brush = pygame.image.load("brush.png").convert_alpha()
  # set the current brush depends on size
  self.brush_now = self.brush.subsurface((0,0), (1, 1))
 
 def start_draw(self, pos):
  self.drawing = True
  self.last_pos = pos
 def end_draw(self):
  self.drawing = False
 
 def set_brush_style(self, style):
  print "* set brush style to", style
  self.style = style
 def get_brush_style(self):
  return self.style
 
 def set_size(self, size):
  if size < 0.5: size = 0.5
  elif size > 50: size = 50
  print "* set brush size to", size
  self.size = size
  self.brush_now = self.brush.subsurface((0,0), (size*2, size*2))
 def get_size(self):
  return self.size
 
 def draw(self, pos):
  if self.drawing:
   for p in self._get_points(pos):
    # draw eveypoint between them
    if self.style == False:
     pygame.draw.circle(self.screen,
       self.color, p, self.size)
    else:
     self.screen.blit(self.brush_now, p)
 
   self.last_pos = pos
 
 def _get_points(self, pos):
  """ Get all points between last_point ~ now_point. """
  points = [ (self.last_pos[0], self.last_pos[1]) ]
  len_x = pos[0] - self.last_pos[0]
  len_y = pos[1] - self.last_pos[1]
  length = math.sqrt(len_x ** 2 + len_y ** 2)
  step_x = len_x / length
  step_y = len_y / length
  for i in xrange(int(length)):
   points.append(
     (points[-1][0] + step_x, points[-1][1] + step_y))
  points = map(lambda x:(int(0.5+x[0]), int(0.5+x[1])), points)
  # return light-weight, uniq list
  return list(set(points))

我們增加了幾個方法,_get_points()返回上一個點到現在點之間所有的點(這話聽著真別扭),draw根據這些點填充。
同時我們把get_size()、set_size()也加上了,用來設定當前筆刷的大小。
而變化最大的,則是set_style()和get_style(),我們現在載入一個PNG圖片作為筆刷的樣式,當style==True的時候,draw不再使用circle填充,而是使用這個PNG樣式,當然,這個樣式大小也是應該可調的,所有我們在set_size()中,會根據size大小實時的調整PNG筆刷。

當然,我們得在主循環中調用set方法,才能讓這些東西工作起來~ 過一會兒再講。再回顧下我們的樣式,還有什么?顏色……我們馬上把顏色設置代碼也加進去吧,太簡單了!我這里就先偷偷懶了~

控制代碼

到現在,我們已經完成了繪圖部分的所有功能了。現在已經可以在屏幕上自由發揮了,但是筆刷的顏色和大小好像不能改啊……我們有這樣的接口你卻不調用,浪費了。
趁熱打鐵趕快把我們這個畫板完成吧~

使用Python編寫簡單的畫圖板程序的示例教程

 

現在實際寫的時候才發現,因為我們設置了顏色需要對刷子也有效,所以實際上set_color方法還有一點點收尾工作需要做:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
def set_color(self, color):
 self.color = color
 for i in xrange(self.brush.get_width()):
  for j in xrange(self.brush.get_height()):
   self.brush.set_at((i, j),
     color + (self.brush.get_at((i, j)).a,))
 
def set_color(self, color):
 self.color = color
 for i in xrange(self.brush.get_width()):
  for j in xrange(self.brush.get_height()):
   self.brush.set_at((i, j),
     color + (self.brush.get_at((i, j)).a,))

也就是在設定color的時候,順便把筆刷的顏色也改了,但是要保留原來的alpha值,其實也很簡單就是了……

按鈕菜單部分

上圖可以看到,按鈕部分分別為鉛筆、毛筆、尺寸大小、(當前樣式)、顏色選擇者幾個組成。我們只以筆刷選擇為例講解一下,其他的都是類似的。

?
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
# 初始化部分
  self.sizes = [
    pygame.image.load("big.png").convert_alpha(),
    pygame.image.load("small.png").convert_alpha()
   ]
  self.sizes_rect = []
  for (i, img) in enumerate(self.sizes):
   rect = pygame.Rect(10 + i * 32, 138, 32, 32)
   self.sizes_rect.append(rect)
 
# 繪制部分
  for (i, img) in enumerate(self.pens):
   self.screen.blit(img, self.pens_rect[i].topleft)
 
# 點擊判斷部分
  for (i, rect) in enumerate(self.pens_rect):
   if rect.collidepoint(pos):
    self.brush.set_brush_style(bool(i))
    return True
 
# 初始化部分
  self.sizes = [
    pygame.image.load("big.png").convert_alpha(),
    pygame.image.load("small.png").convert_alpha()
   ]
  self.sizes_rect = []
  for (i, img) in enumerate(self.sizes):
   rect = pygame.Rect(10 + i * 32, 138, 32, 32)
   self.sizes_rect.append(rect)
 
# 繪制部分
  for (i, img) in enumerate(self.pens):
   self.screen.blit(img, self.pens_rect[i].topleft)
 
# 點擊判斷部分
  for (i, rect) in enumerate(self.pens_rect):
   if rect.collidepoint(pos):
    self.brush.set_brush_style(bool(i))
    return True

這些代碼實際上是我這個例子最想給大家說明的地方,按鈕式我們從未接觸過的東西,然而游戲中按鈕的應用我都不必說。

不過這代碼也都不困難,基本都是我們學過的東西,只不過變換了一下組合而已,我稍微說明一下:

初始化部分:讀入圖標,并給每個圖標一個Rect
繪制部分: 根據圖表的Rect繪制圖表
點擊判斷部分:根據點擊的位置,依靠“碰撞”來判斷這個按鈕是否被點擊,若點擊了,則做相應的操作(這里是設置樣式)后返回True。這里的collidepoint()是新內容,也就是Rect的“碰撞”函數,它接收一個坐標,如果在Rect內部,就返回True,否則False。

好像也就如此,有了一定的知識積累后,新東西的學習也變得易如反掌了。

在這個代碼中,為了明晰,我把各個按鈕按照功能都分成了好幾組,在實際應用中按鈕數量很多的時候可能并不合適,請自己斟酌。

完整代碼

OK,這就結束了~ 下面把整個代碼貼出來。不過,我是一邊寫代碼一遍寫文章,思路不是很連貫,而且python也好久不用了……如果有哪里寫的有問題(沒有就怪了),還請不吝指出!

?
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
import pygame
from pygame.locals import *
import math
 
# 2011/08/27 Version 1, first imported
 
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
  self.last_pos = None
  self.space = 1
  # if style is True, normal solid brush
  # if style is False, png brush
  self.style = False
  # load brush style png
  self.brush = pygame.image.load("brush.png").convert_alpha()
  # set the current brush depends on size
  self.brush_now = self.brush.subsurface((0,0), (1, 1))
 
 def start_draw(self, pos):
  self.drawing = True
  self.last_pos = pos
 def end_draw(self):
  self.drawing = False
 
 def set_brush_style(self, style):
  print "* set brush style to", style
  self.style = style
 def get_brush_style(self):
  return self.style
 
 def get_current_brush(self):
  return self.brush_now
 
 def set_size(self, size):
  if size < 0.5: size = 0.5
  elif size > 32: size = 32
  print "* set brush size to", size
  self.size = size
  self.brush_now = self.brush.subsurface((0,0), (size*2, size*2))
 def get_size(self):
  return self.size
 
 def set_color(self, color):
  self.color = color
  for i in xrange(self.brush.get_width()):
   for j in xrange(self.brush.get_height()):
    self.brush.set_at((i, j),
      color + (self.brush.get_at((i, j)).a,))
 def get_color(self):
  return self.color
 
 def draw(self, pos):
  if self.drawing:
   for p in self._get_points(pos):
    # draw eveypoint between them
    if self.style == False:
     pygame.draw.circle(self.screen, self.color, p, self.size)
    else:
     self.screen.blit(self.brush_now, p)
 
   self.last_pos = pos
 
 def _get_points(self, pos):
  """ Get all points between last_point ~ now_point. """
  points = [ (self.last_pos[0], self.last_pos[1]) ]
  len_x = pos[0] - self.last_pos[0]
  len_y = pos[1] - self.last_pos[1]
  length = math.sqrt(len_x ** 2 + len_y ** 2)
  step_x = len_x / length
  step_y = len_y / length
  for i in xrange(int(length)):
   points.append(
     (points[-1][0] + step_x, points[-1][1] + step_y))
  points = map(lambda x:(int(0.5+x[0]), int(0.5+x[1])), points)
  # return light-weight, uniq integer point list
  return list(set(points))
 
class Menu():
 def __init__(self, screen):
  self.screen = screen
  self.brush = None
  self.colors = [
    (0xff, 0x00, 0xff), (0x80, 0x00, 0x80),
    (0x00, 0x00, 0xff), (0x00, 0x00, 0x80),
    (0x00, 0xff, 0xff), (0x00, 0x80, 0x80),
    (0x00, 0xff, 0x00), (0x00, 0x80, 0x00),
    (0xff, 0xff, 0x00), (0x80, 0x80, 0x00),
    (0xff, 0x00, 0x00), (0x80, 0x00, 0x00),
    (0xc0, 0xc0, 0xc0), (0xff, 0xff, 0xff),
    (0x00, 0x00, 0x00), (0x80, 0x80, 0x80),
   ]
  self.colors_rect = []
  for (i, rgb) in enumerate(self.colors):
   rect = pygame.Rect(10 + i % 2 * 32, 254 + i / 2 * 32, 32, 32)
   self.colors_rect.append(rect)
 
  self.pens = [
    pygame.image.load("pen1.png").convert_alpha(),
    pygame.image.load("pen2.png").convert_alpha()
   ]
  self.pens_rect = []
  for (i, img) in enumerate(self.pens):
   rect = pygame.Rect(10, 10 + i * 64, 64, 64)
   self.pens_rect.append(rect)
 
  self.sizes = [
    pygame.image.load("big.png").convert_alpha(),
    pygame.image.load("small.png").convert_alpha()
   ]
  self.sizes_rect = []
  for (i, img) in enumerate(self.sizes):
   rect = pygame.Rect(10 + i * 32, 138, 32, 32)
   self.sizes_rect.append(rect)
 
 def set_brush(self, brush):
  self.brush = brush
 
 def draw(self):
  # draw pen style button
  for (i, img) in enumerate(self.pens):
   self.screen.blit(img, self.pens_rect[i].topleft)
  # draw < > buttons
  for (i, img) in enumerate(self.sizes):
   self.screen.blit(img, self.sizes_rect[i].topleft)
  # draw current pen / color
  self.screen.fill((255, 255, 255), (10, 180, 64, 64))
  pygame.draw.rect(self.screen, (0, 0, 0), (10, 180, 64, 64), 1)
  size = self.brush.get_size()
  x = 10 + 32
  y = 180 + 32
  if self.brush.get_brush_style():
   x = x - size
   y = y - size
   self.screen.blit(self.brush.get_current_brush(), (x, y))
  else:
   pygame.draw.circle(self.screen,
     self.brush.get_color(), (x, y), size)
  # draw colors panel
  for (i, rgb) in enumerate(self.colors):
   pygame.draw.rect(self.screen, rgb, self.colors_rect[i])
 
 def click_button(self, pos):
  # pen buttons
  for (i, rect) in enumerate(self.pens_rect):
   if rect.collidepoint(pos):
    self.brush.set_brush_style(bool(i))
    return True
  # size buttons
  for (i, rect) in enumerate(self.sizes_rect):
   if rect.collidepoint(pos):
    if i: # i == 1, size down
     self.brush.set_size(self.brush.get_size() - 0.5)
    else:
     self.brush.set_size(self.brush.get_size() + 0.5)
    return True
  # color buttons
  for (i, rect) in enumerate(self.colors_rect):
   if rect.collidepoint(pos):
    self.brush.set_color(self.colors[i])
    return True
  return False
 
class Painter():
 def __init__(self):
  self.screen = pygame.display.set_mode((800, 600))
  pygame.display.set_caption("Painter")
  self.clock = pygame.time.Clock()
  self.brush = Brush(self.screen)
  self.menu = Menu(self.screen)
  self.menu.set_brush(self.brush)
 
 def run(self):
  self.screen.fill((255, 255, 255))
  while True:
   # max fps limit
   self.clock.tick(30)
   for event in pygame.event.get():
    if event.type == QUIT:
     return
    elif event.type == KEYDOWN:
     # press esc to clear screen
     if event.key == K_ESCAPE:
      self.screen.fill((255, 255, 255))
    elif event.type == MOUSEBUTTONDOWN:
     # <= 74, coarse judge here can save much time
     if ((event.pos)[0] <= 74 and
       self.menu.click_button(event.pos)):
      # if not click on a functional button, do drawing
      pass
     else:
      self.brush.start_draw(event.pos)
    elif event.type == MOUSEMOTION:
     self.brush.draw(event.pos)
    elif event.type == MOUSEBUTTONUP:
     self.brush.end_draw()
 
   self.menu.draw()
   pygame.display.update()
 
if __name__ == '__main__':
 app = Painter()
 app.run()
 
import pygame
from pygame.locals import *
import math
 
# 2011/08/27 Version 1, first imported
 
class Brush():
 def __init__(self, screen):
  self.screen = screen
  self.color = (0, 0, 0)
  self.size = 1
  self.drawing = False
  self.last_pos = None
  self.space = 1
  # if style is True, normal solid brush
  # if style is False, png brush
  self.style = False
  # load brush style png
  self.brush = pygame.image.load("brush.png").convert_alpha()
  # set the current brush depends on size
  self.brush_now = self.brush.subsurface((0,0), (1, 1))
 
 def start_draw(self, pos):
  self.drawing = True
  self.last_pos = pos
 def end_draw(self):
  self.drawing = False
 
 def set_brush_style(self, style):
  print "* set brush style to", style
  self.style = style
 def get_brush_style(self):
  return self.style
 
 def get_current_brush(self):
  return self.brush_now
 
 def set_size(self, size):
  if size < 0.5: size = 0.5
  elif size > 32: size = 32
  print "* set brush size to", size
  self.size = size
  self.brush_now = self.brush.subsurface((0,0), (size*2, size*2))
 def get_size(self):
  return self.size
 
 def set_color(self, color):
  self.color = color
  for i in xrange(self.brush.get_width()):
   for j in xrange(self.brush.get_height()):
    self.brush.set_at((i, j),
      color + (self.brush.get_at((i, j)).a,))
 def get_color(self):
  return self.color
 
 def draw(self, pos):
  if self.drawing:
   for p in self._get_points(pos):
    # draw eveypoint between them
    if self.style == False:
     pygame.draw.circle(self.screen, self.color, p, self.size)
    else:
     self.screen.blit(self.brush_now, p)
 
   self.last_pos = pos
 
 def _get_points(self, pos):
  """ Get all points between last_point ~ now_point. """
  points = [ (self.last_pos[0], self.last_pos[1]) ]
  len_x = pos[0] - self.last_pos[0]
  len_y = pos[1] - self.last_pos[1]
  length = math.sqrt(len_x ** 2 + len_y ** 2)
  step_x = len_x / length
  step_y = len_y / length
  for i in xrange(int(length)):
   points.append(
     (points[-1][0] + step_x, points[-1][1] + step_y))
  points = map(lambda x:(int(0.5+x[0]), int(0.5+x[1])), points)
  # return light-weight, uniq integer point list
  return list(set(points))
 
class Menu():
 def __init__(self, screen):
  self.screen = screen
  self.brush = None
  self.colors = [
    (0xff, 0x00, 0xff), (0x80, 0x00, 0x80),
    (0x00, 0x00, 0xff), (0x00, 0x00, 0x80),
    (0x00, 0xff, 0xff), (0x00, 0x80, 0x80),
    (0x00, 0xff, 0x00), (0x00, 0x80, 0x00),
    (0xff, 0xff, 0x00), (0x80, 0x80, 0x00),
    (0xff, 0x00, 0x00), (0x80, 0x00, 0x00),
    (0xc0, 0xc0, 0xc0), (0xff, 0xff, 0xff),
    (0x00, 0x00, 0x00), (0x80, 0x80, 0x80),
   ]
  self.colors_rect = []
  for (i, rgb) in enumerate(self.colors):
   rect = pygame.Rect(10 + i % 2 * 32, 254 + i / 2 * 32, 32, 32)
   self.colors_rect.append(rect)
 
  self.pens = [
    pygame.image.load("pen1.png").convert_alpha(),
    pygame.image.load("pen2.png").convert_alpha()
   ]
  self.pens_rect = []
  for (i, img) in enumerate(self.pens):
   rect = pygame.Rect(10, 10 + i * 64, 64, 64)
   self.pens_rect.append(rect)
 
  self.sizes = [
    pygame.image.load("big.png").convert_alpha(),
    pygame.image.load("small.png").convert_alpha()
   ]
  self.sizes_rect = []
  for (i, img) in enumerate(self.sizes):
   rect = pygame.Rect(10 + i * 32, 138, 32, 32)
   self.sizes_rect.append(rect)
 
 def set_brush(self, brush):
  self.brush = brush
 
 def draw(self):
  # draw pen style button
  for (i, img) in enumerate(self.pens):
   self.screen.blit(img, self.pens_rect[i].topleft)
  # draw < > buttons
  for (i, img) in enumerate(self.sizes):
   self.screen.blit(img, self.sizes_rect[i].topleft)
  # draw current pen / color
  self.screen.fill((255, 255, 255), (10, 180, 64, 64))
  pygame.draw.rect(self.screen, (0, 0, 0), (10, 180, 64, 64), 1)
  size = self.brush.get_size()
  x = 10 + 32
  y = 180 + 32
  if self.brush.get_brush_style():
   x = x - size
   y = y - size
   self.screen.blit(self.brush.get_current_brush(), (x, y))
  else:
   pygame.draw.circle(self.screen,
     self.brush.get_color(), (x, y), size)
  # draw colors panel
  for (i, rgb) in enumerate(self.colors):
   pygame.draw.rect(self.screen, rgb, self.colors_rect[i])
 
 def click_button(self, pos):
  # pen buttons
  for (i, rect) in enumerate(self.pens_rect):
   if rect.collidepoint(pos):
    self.brush.set_brush_style(bool(i))
    return True
  # size buttons
  for (i, rect) in enumerate(self.sizes_rect):
   if rect.collidepoint(pos):
    if i: # i == 1, size down
     self.brush.set_size(self.brush.get_size() - 0.5)
    else:
     self.brush.set_size(self.brush.get_size() + 0.5)
    return True
  # color buttons
  for (i, rect) in enumerate(self.colors_rect):
   if rect.collidepoint(pos):
    self.brush.set_color(self.colors[i])
    return True
  return False
 
class Painter():
 def __init__(self):
  self.screen = pygame.display.set_mode((800, 600))
  pygame.display.set_caption("Painter")
  self.clock = pygame.time.Clock()
  self.brush = Brush(self.screen)
  self.menu = Menu(self.screen)
  self.menu.set_brush(self.brush)
 
 def run(self):
  self.screen.fill((255, 255, 255))
  while True:
   # max fps limit
   self.clock.tick(30)
   for event in pygame.event.get():
    if event.type == QUIT:
     return
    elif event.type == KEYDOWN:
     # press esc to clear screen
     if event.key == K_ESCAPE:
      self.screen.fill((255, 255, 255))
    elif event.type == MOUSEBUTTONDOWN:
     # <= 74, coarse judge here can save much time
     if ((event.pos)[0] <= 74 and
       self.menu.click_button(event.pos)):
      # if not click on a functional button, do drawing
      pass
     else:
      self.brush.start_draw(event.pos)
    elif event.type == MOUSEMOTION:
     self.brush.draw(event.pos)
    elif event.type == MOUSEBUTTONUP:
     self.brush.end_draw()
 
   self.menu.draw()
   pygame.display.update()
 
if __name__ == '__main__':
 app = Painter()
 app.run()

200行左右,注釋也不是很多,因為在這兩篇文章里都講了,有哪里不明白的請留言,我會根據實際情況再改改。

本次使用的資源文件打包

這次的pygame知識點:

  • 屏幕Surface和圖像Surface
  • 圖像繪制和圖形繪制(是不是有人不明白“圖像”和“圖形”的區別?簡單的說,圖像指的是那些圖片文件,圖形指的是用命令畫出來形狀)
  • 按鈕的實現(新內容)

認真的朋友一定發現了本次沒有涉及到動畫和聲音,畢竟這次只是簡單的例子,太復雜了不免讓人生畏。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美日韩成人一区二区 | 免费看黄色三级毛片 | 天天都色视频 | 黄色影院在线观看视频 | 亚洲射情 | 日日鲁一鲁视频 | 日韩大片在线永久观看视频网站免费 | 亚洲精品一区二区三区在线看 | 精品成人av一区二区三区 | 欧美一级黄 | 国产精品免费麻豆入口 | 国产精选91 | 黄色特级一级片 | 成人黄色免费网站 | 久章草影院 | 极品美女一级毛片 | av不卡毛片| 亚洲影视在线观看 | 青青国产在线视频 | 日本欧美国产 | 色蜜桃av | 日韩视频一区二区三区在线观看 | 欧美精品一二三区 | 91九色精品| av在线在线 | 久久久久久久久国产 | 亚洲精品午夜电影 | 精品国产99久久久久久宅男i | 99麻豆久久久国产精品免费 | 欧美 中文字幕 | 欧美a级在线免费观看 | 久久久精品视频国产 | 国产又粗又爽又深的免费视频 | 国产精品99久久久久久大便 | 黄色av免费网站 | 色视频91| 欧美精品日日鲁夜夜添 | 好吊色37pao在线观看 | 国产成人精品免高潮在线观看 | 97中文字幕第一一一页 | 国产一级毛片国语版 |