学校的课设总算是告一段落,现在有时间分享一下代码和心得了。这次的文章是回应之前的雏形版代码的,这次的可是完全版哦。
我们先来看一下效果吧!
效果总归还行吧,代码也比较简短,只有170行。再此推荐你看我之前关于这个题目的文章,接下来我直接代码讲解了。
# -*- coding:utf-8 -*-
#print('资源加载中,稍等片刻……')
from tkinter import *
from PIL import Image,ImageTk
from threading import Thread,Lock
from time import sleep
from random import randint
"""哲学家类"""
class Philosopher(Thread):
def __init__(self, index,forks,numForks,labels):
Thread.__init__(self)
self.index = index
self.forks=forks
self.numForks=numForks
self.rightFork = forks[self.index]
self.leftFork = forks[(self.index + 1) % numForks]
self.bm_thinking=ImageTk.PhotoImage(Image.open('img/thinking.png').resize((150,150),Image.ANTIALIAS))
self.bm_eating=ImageTk.PhotoImage(Image.open('img/eating.png').resize((150,150),Image.ANTIALIAS))
self.bm_waiting=ImageTk.PhotoImage(Image.open('img/waiting.png').resize((150,150),Image.ANTIALIAS))
self.bm_another=ImageTk.PhotoImage(Image.open('img/another.png').resize((150,150),Image.ANTIALIAS))
def run(self):
while True:
self.thinking()
self.hungry()
while True:
sleep(0.5)
if hobby.get()==True:#获取按钮的状态
self.leftFork.pickup()
labels[self.index].configure(image=self.bm_another)
labels[self.index].image=self.bm_another
text.insert(END,"Philosopher %s pick up left Fork.\n"%(self.index))
sleep(0.5)
self.rightFork.pickup()
text.insert(END,"Philosopher %s pick up right Fork.\n"%(self.index))
self.dining()
self.leftFork.putdown()
text.insert(END,"Philosopher %s put down left Fork.\n"%(self.index))
self.rightFork.putdown()
text.insert(END,"Philosopher %s put down right Fork.\n"%(self.index))
break
else:
if self.leftFork.use==False:
if self.rightFork.use==False:
self.leftFork.pickup()
text.insert(END,"Philosopher %s pick up left Fork.\n"%(self.index))
self.rightFork.pickup()
text.insert(END,"Philosopher %s pick up right Fork.\n"%(self.index))
self.dining()
self.leftFork.putdown()
text.insert(END,"Philosopher %s put down left Fork.\n"%(self.index))
self.rightFork.putdown()
text.insert(END,"Philosopher %s put down right Fork.\n"%(self.index))
break
def dining(self):
text.insert(END,"Philosopher %s starts to eat.\n"%(self.index))
labels[self.index].configure(image=self.bm_eating)
labels[self.index].image=self.bm_eating
sleep(randint(2,4))
text.insert(END,"Philosopher %s finishes eating.\n"%(self.index))
def thinking(self):
text.insert(END,"Philosopher %s is thinking.\n"%(self.index))
labels[self.index].configure(image=self.bm_thinking)
labels[self.index].image=self.bm_thinking
if not hobby2.get():#获取按钮的状态
sleep(randint(2,5))
def hungry(self):
text.insert(END,"Philosopher %s is hungry.\n"%(self.index))
labels[self.index].configure(image=self.bm_waiting)
labels[self.index].image=self.bm_waiting
sleep(1)
python图形化的特点,写代码的时候要和Tkinter里的组件结合,所以有时候会不知道类里的使用到的组件是哪来的,可以回到主程序里寻找。
"""叉子类"""
class Fork:
def __init__(self, index,label_forks):
self.index = index
self.forks=label_forks
self._lock = Lock()
self.bm_fork=ImageTk.PhotoImage(Image.open('img/fork.png').resize((70,130),Image.ANTIALIAS))
self.bm_nothing=ImageTk.PhotoImage(Image.open('img/nothing.png').resize((70,130),Image.ANTIALIAS))
self.use=False
for i in self.forks:
i.configure(image=self.bm_fork)
def pickup(self):
"""叉子的消失其实就是拿一张和背景色相同的图片来遮挡叉子的图片"""
self._lock.acquire()
self.use=True
self.forks[self.index].configure(image=self.bm_nothing)
self.forks[self.index].image=self.bm_nothing
def putdown(self):
self._lock.release()
self.use=False
self.forks[self.index].configure(image=self.bm_fork)
self.forks[self.index].image=self.bm_fork
def main():
text.delete('0.0','end')#清除文本框中的所有内容
numPhilosophers = numForks = 5
# 创建叉子与哲学家实例
forks = [Fork(idx,label_forks) for idx in range(numForks)]
philosophers = [Philosopher(idx,forks,numForks,labels)for idx in range(numPhilosophers)]
# 开启所有的哲学家线程
for philosopher in philosophers:
philosopher.start()
def author():#关于作者的说明,我没有用文本形式而是图片呈现
"""必要一提的就是Tkinter不支持二级窗口呈现图片,所以要用Toplevel"""
newroot=Toplevel()
bm_about = ImageTk.PhotoImage(Image.open('img/about.png'))
aboutme=Label(newroot,image=bm_about)
aboutme.pack()
newroot.mainloop()
def detail_show():#“说明”的内容
newroot2=Toplevel()
bm_details = ImageTk.PhotoImage(Image.open('img/details.png'))
details_label=Label(newroot2,image=bm_details)
details_label.pack()
newroot2.mainloop()
if __name__ == '__main__':
root = Tk()
root.title('哲学家问题')
root.geometry('1000x750')
start=Button(root,text='开始',font=('Arial',12),command=main,relief='raised')
start.place(x=100,y=0)
tip=Button(root,text='关于',font=('Arial',12),command=author,relief='raised')
tip.place(x=180,y=0)
hobby=BooleanVar()
isDeathLock=Checkbutton(root,text='允许死锁',font=('Arial',12),variable=hobby,relief='raised')
isDeathLock.place(x=260,y=0)
hobby2=BooleanVar()
death=Checkbutton(root,text='饥饿模式',font=('Arial',12),variable=hobby2,relief='raised')
death.place(x=400,y=0)
details=Button(root,text='说明',font=('Arial',12),command=detail_show,relief='raised')
details.place(x=550,y=0)
scroll = Scrollbar()
text=Text(root,width=35,height=50)
scroll.pack(side=RIGHT,fill=Y)
text.pack(side=RIGHT)
scroll.config(command=text.yview)
text.config(yscrollcommand=scroll.set)
img_init = Image.open('img/init.png').resize((150,150),Image.BILINEAR)
bm_init=ImageTk.PhotoImage(img_init)
labels=[]
for i in range(5):
temp=Label(root,image=bm_init)
labels.append(temp)
labels[0].place(x=400,y=100)
labels[1].place(x=520,y=350)
labels[2].place(x=250,y=570)
labels[3].place(x=50,y=350)
labels[4].place(x=150,y=100)
#加载餐桌图像
img_table = Image.open('img/table.png').resize((250,200),Image.BILINEAR)
bm_table = ImageTk.PhotoImage(img_table)
label_table=Label(root,image=bm_table)
label_table.image=bm_table
label_table.place(x=240,y=300)
#加载叉子类
img_fork = Image.open('img/fork.png').resize((70,130),Image.BILINEAR)
bm_fork = ImageTk.PhotoImage(img_fork)
label_forks=[]
for i in range(5):
temp=Label(root,image=bm_fork)
label_forks.append(temp)
label_forks[0].place(x=320,y=100)
label_forks[1].place(x=600,y=150)
label_forks[2].place(x=500,y=550)
label_forks[3].place(x=150,y=550)
label_forks[4].place(x=75,y=175)
print('加载完毕')
root.mainloop()
大功告成,代码自取,图片自己挑选设计,死锁的解决换种算法,我使用的是简单的”左右手都有叉子才进餐“的算法。关于使用pyinstaller对py文件打包可以参考我的另外一篇文章。喜欢就点个赞再走吧!