Python Tkinter 哲学家问题可视化

Python Tkinter 哲学家问题可视化

学校的课设总算是告一段落,现在有时间分享一下代码和心得了。这次的文章是回应之前的雏形版代码的,这次的可是完全版哦。
我们先来看一下效果吧!
在这里插入图片描述
效果总归还行吧,代码也比较简短,只有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文件打包可以参考我的另外一篇文章。喜欢就点个赞再走吧!

猜你喜欢

转载自blog.csdn.net/weixin_43594279/article/details/106951739