python-tkinter学习实例

  在好友的邀请下,尝试用tkinter做一个卡牌的普通界面显示,正好练习下python的写法。
  花了两天学习,写了两天代码,做了个最基本的demo。显示如下:

其中需要引入的第三方库主要有,PIL、PILLOW,其它的都是直接引入即可。

1.1、这里贴下下载地址,以WINDOWS系统为例:


PILwin32:http://files.cnblogs.com/files/pcat/PILwin32.zip

PILwin64:http://files.cnblogs.com/files/pcat/PILwin64.zip

1.2、windows安装Pillow

pip install Pillow
或者在http://www.lfd.uci.edu/~gohlke/pythonlibs/#pillow 下载wheel文件使用pip安装

程序中用到的图片主要有:

需要图片资源的小伙伴可以自行上git上下载:

https://github.com/ishikota/PyPokerGUI

pypokergui--server--static

贴上程序的源码,仅供参考:

  1 # -*- coding: utf-8 -*-
  2 from Tkinter import *
  3 from PIL import Image,ImageTk
  4 
  5 import Image,math,random,time,sched
  6 import threading as thd
  7 class card2:
  8     #定义全局变量
  9     #总牌数
 10     num_list = ['3', '4', '5', '6', '7', '8', '9','T', 'J','Q','K', 'A','2']
 11     # 全局变量纪录玩家当前要打出的牌数字
 12     #当前牌面字符串
 13     str_num = '';
 14     #当前牌面字符串在num_list中的位置
 15     index_num = -1;
 16     # 中间桌面上牌的大小
 17     mid_num = -2;
 18     #判断是否会生成重复的牌
 19     check_list = [];
 20     #记录当前回合数
 21     round_num = 1;
 22     #当前玩家手中牌位置
 23     cur_position = 0;
 24     #定义玩家当前手中牌的集合
 25     player_card_list = [];
 26     player1_card_list = [];
 27     player2_card_list = [];
 28     player3_card_list = [];
 29     player4_card_list = [];
 30 
 31     #变量判断玩家身份,默认为玩家
 32     cur_identify = 1;
 33 
 34     def __init__(self):
 35         self.tk = Tk()
 36         #tk.geometry('1200x1600')
 37         self.tk.title('A Easy Card Game')
 38 
 39         self.img = Image.open('images/poker_pot.png')
 40         self.w_box = 120
 41         self.h_box = 120
 42         self.w, self.h = self.img.size
 43         # w,h = img2.size
 44         # 缩放图像让它保持比例,同时限制在一个矩形框范围内
 45         self.img_resized = self.resize(self.w, self.h, self.w_box, self.h_box, self.img)
 46         self.photo = ImageTk.PhotoImage(self.img_resized)
 47         # frm_TL = Frame(bg = 'WHITE',width = 300, height = 200)
 48         self.frm_T = Frame(bg='white', width=300, height=200)
 49         self.frm_L = Frame(bg='white', width=300, height=400)
 50         self.frm_M = Frame(bg='white', width=200, height=400)
 51         self.frm_R = Frame(bg='white', width=300, height=400)
 52         self.frm_B = Frame(bg='white', width=400, height=200)
 53         # frm_TL.grid(row=0,column=0)
 54         self.frm_T.grid(row=0, column=1)
 55         self.frm_L.grid(row=1, column=0)
 56         self.frm_M.grid(row=1, column=1)
 57         self.frm_R.grid(row=1, column=2)
 58         self.frm_B.grid(row=2, column=1)
 59         # Top
 60         Label(self.frm_T, text="Player3", font=('Arial', 16)).grid(column=1, sticky=N)
 61         Button(self.frm_T, text="重新发牌", command=self.replay, width=8, height=1,
 62                font=('Arial', 16)).grid(row=0, column=3)
 63         self.frm_T_label_L = Label(self.frm_T, image=self.photo)
 64         self.frm_T_label_L.image = self.photo
 65         self.frm_T_label_L.grid(row=1, column=0, sticky=E)
 66         # frm_T_label_L.grid(row=1,column=1,columnspan=2,rowspan=2,sticky=W+E+N+S,padx=5,pady=5)
 67         self.frm_T_label_M = Label(self.frm_T, image=self.photo)
 68         self.frm_T_label_M.image = self.photo
 69         self.frm_T_label_M.grid(row=1, column=1,padx=10, sticky=E)
 70         self.frm_T_label_R = Label(self.frm_T, image=self.photo)
 71         self.frm_T_label_R.image = self.photo
 72         self.frm_T_label_R.grid(row=1, column=2, sticky=E)
 73 
 74         # Left
 75         Label(self.frm_L, text="Player4", font=('Arial', 16)).grid(row=1, column=0, sticky=N)
 76         self.frm_L_label_T = Label(self.frm_L, image=self.photo)
 77         self.frm_L_label_T.image = self.photo
 78         self.frm_L_label_T.grid(row=0, column=1, sticky=E)
 79         self.frm_L_label_T = Label(self.frm_L, image=self.photo)
 80         self.frm_L_label_T.image = self.photo
 81         self.frm_L_label_T.grid(row=1, column=1, sticky=E)
 82         self.frm_L_label_T = Label(self.frm_L, image=self.photo)
 83         self.frm_L_label_T.image = self.photo
 84         self.frm_L_label_T.grid(row=2, column=1, sticky=E)
 85 
 86         # Middle
 87         self.frm_M_label_T = Label(self.frm_M, image=self.photo)
 88         self.frm_M_label_T.image = self.photo
 89         self.frm_M_label_T.grid(row=1, column=0, sticky=E)
 90         self.frm_M_text = Text(self.frm_M, width=30, height=6, bg='Green', font=('Verdana', 15))
 91 
 92         #self.frm_M_text.insert('1.0', 'this is '+str(self.round_num)+' round
')
 93         #self.frm_M_text.insert(END, 'last round')
 94         self.frm_M_text.grid(row=2, column=0, columnspan=2)
 95 
 96         # Right  frm_R
 97         self.frm_R_label_T = Label(self.frm_R, image=self.photo)
 98         self.frm_R_label_T.image = self.photo
 99         self.frm_R_label_T.grid(row=0, column=0, sticky=E)
100         self.frm_R_label_T = Label(self.frm_R, image=self.photo)
101         self.frm_R_label_T.image = self.photo
102         self.frm_R_label_T.grid(row=1, column=0, sticky=E)
103         self.frm_R_label_T = Label(self.frm_R, image=self.photo)
104         self.frm_R_label_T.image = self.photo
105         self.frm_R_label_T.grid(row=2, column=0, sticky=E)
106         Label(self.frm_R, text="Player2", font=('Arial', 16)).grid(row=1, column=1, sticky=N)
107 
108         # 初始化玩家手中牌
109         self.load_sys()
110 
111         self.main_start()
112 
113         self.frm_B_label_T_4 = Label(self.frm_B, image=self.photo)
114         self.frm_B_label_T_4.image = self.photo
115         self.frm_B_label_T_4.grid(row=0, column=3, sticky=E)
116         Label(self.frm_B, text="Player1", font=('Arial', 16)).grid(row=1, column=1, sticky=N)
117         Button(self.frm_B, text="出牌", command=self.discard, width=6, height=1,
118                font=('Arial', 16)).grid(row=1, column=3)
119         Button(self.frm_B, text="PASS", command=self.player_pass, width=6, height=1,
120                font=('Arial', 16)).grid(row=1, column=4)
121 
122     def resize(self,w, h, w_box, h_box, pil_image):
123         '''''
124         resize a pil_image object so it will fit into
125         a box of size w_box times h_box, but retain aspect ratio
126         对一个pil_image对象进行缩放,让它在一个矩形框内,还能保持比例
127         '''
128 
129         f1 = 1.0 * w_box / w  # 1.0 forces float division in Python2
130         f2 = 1.0 * h_box / h
131         factor = min([f1, f2])
132         # print(f1, f2, factor) # test
133         # use best down-sizing filter
134         width = int(w * factor)
135         height = int(h * factor)
136         return pil_image.resize((width, height), Image.ANTIALIAS)
137     def replay(self):
138         self.load_sys()
139 
140     #初始化玩家手中牌
141     def load_sys(self):
142         # 初始化当前玩家手中牌集合,先重置
143         self.player1_card_list = []
144         self.player2_card_list = []
145         self.check_list = []
146         self.cur_identify = 1
147         for i in range(3):
148             num = random.randint(0,12)
149             #判断是否生成重复的牌,去重
150             while self.check_list.__contains__(num):
151                 num = random.randint(0, 12)
152             cur_str = self.num_list[num]
153             photo_current = ImageTk.PhotoImage(self.resize(self.w, self.h, self.w_box, self.h_box, Image.open('images/card_C' + str(cur_str) + '.png')))
154             frm_B_label_T_1 = Label(self.frm_B, image=photo_current)
155             frm_B_label_T_1.image = photo_current
156             frm_B_label_T_1.grid(row=0, column=i,sticky=E)
157             frm_B_label_T_1.bind('<ButtonRelease-1>', self.handlerAdaptor(self.choose, cur_str,i))
158             self.check_list.append(num)
159             self.player1_card_list.append(cur_str)
160             #生成玩家2手中的牌
161             num2 = random.randint(0, 12)
162             # 判断是否生成重复的牌,去重
163             while self.check_list.__contains__(num2):
164                 num2 = random.randint(0, 12)
165             cur_str2 = self.num_list[num2]
166             self.check_list.append(num2)
167             self.player2_card_list.append(cur_str2)
168 
169         print(self.player1_card_list)
170         print(self.player2_card_list)
171         #记录当前轮数并递增
172         self.frm_M_text.insert('1.0', 'this is ' + str(self.round_num) + ' round
')
173         self.round_num+=1
174 
175         # 清空桌面上的牌
176         frm_M_label_T = Label(self.frm_M, image=self.photo)
177         frm_M_label_T.image = self.photo
178         frm_M_label_T.grid(row=1, column=0, sticky=E)
179         # 重置玩家手中当前牌
180         frm_B_label_T_4 = Label(self.frm_B, image=self.photo)
181         frm_B_label_T_4.image = self.photo
182         frm_B_label_T_4.grid(row=0, column=3, sticky=E)
183         #重置桌面上牌的大小
184         self.mid_num = -2
185     # Bottom
186     def choose(self,event,a,position):
187         self.frm_M_text.insert('1.0','Now Your Card Is C'+str(a)+'
')
188         photo_cur = ImageTk.PhotoImage(self.resize(self.w, self.h, self.w_box, self.h_box, Image.open('images/card_C' + str(a) + '.png')))
189         frm_B_label_T_4 = Label(self.frm_B, image=photo_cur)
190         frm_B_label_T_4.image = photo_cur
191         frm_B_label_T_4.grid(row=0, column=3, sticky=E)
192         self.str_num = a
193         self.cur_position = position
194     def handlerAdaptor(self,fun, *kwds):
195         '''''事件处理函数的适配器,相当于中介,此处接收2个参数,那个event是从那里来的呢,我也纳闷,这也许就是python的伟大之处吧'''
196         return lambda event,fun=fun,kwds=kwds: fun(event, *kwds)
197     def discard(self):
198         if self.cur_identify == 1:
199             if self.str_num != '':
200                 self.index_num = self.num_list.index(self.str_num)
201             if self.index_num == -1:
202                 self.frm_M_text.insert('1.0','请选择一张牌
')
203                 #return '请选择一张牌'
204             #判断要打出的牌与桌面上的牌大小
205             elif self.index_num <= self.mid_num:
206                 self.frm_M_text.insert('1.0', '请选择一张大牌
')
207                # return '请选择一张大牌'
208             else:
209                 photo_mid = ImageTk.PhotoImage(self.resize(self.w, self.h, self.w_box, self.h_box, Image.open('images/card_C' + str(self.str_num) + '.png')))
210                 frm_M_label_T = Label(self.frm_M, image=photo_mid)
211                 frm_M_label_T.image = photo_mid
212                 frm_M_label_T.grid(row=1, column=0, sticky=E)
213                 #清空玩家手中当前牌
214                 frm_B_label_T_4 = Label(self.frm_B, image=self.photo)
215                 frm_B_label_T_4.image = self.photo
216                 frm_B_label_T_4.grid(row=0, column=3, sticky=E)
217                 #frm_B_label_T_4.grid_forget()
218                 #给当前桌面牌赋值
219                 self.mid_num = self.index_num
220                 #重置玩家手中牌
221                 frm_B_label_T_X = Label(self.frm_B, image=self.photo)
222                 frm_B_label_T_X.image = self.photo
223                 frm_B_label_T_X.grid(row=0, column=self.cur_position, sticky=E)
224                 self.frm_M_text.insert('1.0', 'Player1 Play The Card!'+ str(self.str_num) +'
')
225                 self.player1_card_list.remove(self.str_num)
226                 if self.player1_card_list.__len__() == 0:
227                     self.frm_M_text.insert('1.0', 'Congratulations! Player1 Win The Game!
')
228                     return
229                 #当玩家打出牌后,切换到电脑2,调用电脑出牌方法
230                 self.cur_identify +=1
231                 self.discard_pc(self.cur_identify)
232         else:
233             self.frm_M_text.insert('1.0', '请等待其它玩家出牌
')
234 
235     #没有可出的牌,切换到下一个对手
236     def player_pass(self):
237         # 重置中间牌的大小
238         self.mid_num = -2
239         #切换玩家
240         self.cur_identify += 1
241         self.discard_pc(self.cur_identify)
242 
243     # def player_pc(self,iden):
244     #     if iden == 2:
245     #         self.player_card_list = self.player2_card_list
246     #
247     #     if iden ==3:
248     #         self.cur_identify = 1
249 
250     def discard_pc(self,iden):
251         card_list_pc = []
252         if iden == 2:
253             for i in range(self.player2_card_list.__len__()):
254                 #将当前牌转化成索引号进行比较大小
255                 self.index_pc_num = self.num_list.index(self.player2_card_list[i])
256 
257                 if self.index_pc_num > self.mid_num:
258                     card_list_pc.append(self.player2_card_list[i])
259             card_list_pc.sort()
260             if len(card_list_pc) > 0:
261                 self.index_pc_num_temp = self.num_list.index(card_list_pc[0])
262                 self.mid_num = self.index_pc_num_temp
263                 photo_mid = ImageTk.PhotoImage(self.resize(self.w, self.h, self.w_box, self.h_box,
264                                                            Image.open('images/card_C' + str(card_list_pc[0]) + '.png')))
265                 frm_M_label_T = Label(self.frm_M, image=photo_mid)
266                 frm_M_label_T.image = photo_mid
267                 frm_M_label_T.grid(row=1, column=0, sticky=E)
268                 self.frm_M_text.insert('1.0', 'Player2 Play The Card!' + str(card_list_pc[0]) + '
')
269                 self.player2_card_list.remove(card_list_pc[0])
270 
271                 if self.player2_card_list.__len__() == 0:
272                     self.frm_M_text.insert('1.0', 'Congratulations! Player2 Win The Game!
')
273                     return
274                 # 当玩家打出牌后,切换到电脑2,调用电脑出牌方法
275                 self.cur_identify += 1
276                 if self.cur_identify == 3:
277                     self.cur_identify = 1
278             elif len(card_list_pc) == 0:
279                 self.frm_M_text.insert('1.0', '没有大过玩家的牌,请玩家出牌
')
280                 #重置中间牌的大小
281                 self.mid_num = -2
282                 self.cur_identify = 1
283 
284     # # 实例化一个sched对象
285     # schedule = sched.scheduler(time.time, time.sleep)
286     def show_time(self):
287         cur_time = time.strftime('%Y-%m-%d %X',time.localtime())
288         top_time_label = Label(self.frm_T, text=cur_time, font=('Arial', 16))
289         top_time_label.grid(column=2, sticky=N)
290         while True:
291             cur_time = time.strftime('%Y-%m-%d %X', time.localtime())
292             top_time_label.configure(text=cur_time)
293             time.sleep(1)
294     def main_start(self):
295         thd.Timer(0, self.show_time).start()
296 def main():
297     d = card2()
298     mainloop()
299 
300 if __name__ == '__main__':
301     main()
View Code

注意:调整图片大小需要用到resize()方法,PNG图片需要用到ImageTk.PhotoImage(self.img_resized)转化方可显示。

增加了定时任务显示当前时间,每秒切换一次,注意不要占用主线程。

提出几个方向以待大神们能完善:

2.1、程序中只启用了player2与玩家互动,可以尝试启用4个。

2.2、只选择了一组牌进行显示,可以尝试加入4组牌,用file文件引入数据。

2.3、不同花色的相同数字比较可以用3.1、3.2、3.3、3.4浮点数比较大小。

2.4、图片显示可以增加更多,遗留的问题是图片重叠显示,感觉用tkinter的grid方式无法实现,可能自己水平有限。

原文地址:https://www.cnblogs.com/lq147760524/p/8283803.html