1. 程式人生 > >python tkinter 屏保

python tkinter 屏保

第一次用python寫的小程式,記錄下。

需求:

  • 屏保可以自己啟動,也可以手動啟動
  • 一旦敲擊鍵盤或者移動滑鼠後,或者其他的引發時間,則停止
  • 如果屏保是一幅畫的話,則沒有畫框
  • 影象的動作是隨機的,具有隨機性,可能包括顏色,大小,多少, 運動方向,變形等
  • 整個世界的構成是:
    • ScreenSaver:

      • 需要一個canvas, 大小與螢幕一致,沒有邊框
    • Ball

      • 顏色,大小,多少, 運動方向,變形等隨機
      • 球能動,可以被呼叫
from tkinter import *
import random

class RandomBall():

   # 定義運動的球的類


    def __init__(self,canvas,scrnwidth,scrnheight):
    #  canvas: 畫布,所有的內容都應該在畫布上呈現出來,此處通過此變數傳入
    #  scrnwidth/scrnheigh:螢幕寬高

    # 球出現的初始位置要隨機,此處位置表示的球的圓心
    # xpos表示位置的x座標
    # print(type(canvas))
        self.canvas = canvas
        self.xpos = random.randint(10,int(scrnwidth) - 20)

    # ypos表示位置的y座標
        self.ypos = random.randint(10, int(scrnwidth) - 20)
    # 定義球運動的速度
    # 模擬運動:不斷的擦掉原來畫,然後在一個新的地方再從新繪製
    # 此處xvelocity模擬x軸方向運動
        self.xvelocity = random.randint(4, 20)
    # 同理,yvelocity模擬的是y軸方向運動
        self.yvelocity = random.randint(4, 20)
    # 定義螢幕的大小
        self.scrnwidth = scrnwidth
    # 定義螢幕的高度
        self.scrnheight = scrnheight
    # 球的大小隨機
    # 此處球的大小用半徑表示
        self.radius = random.randint(20, 120)

    # 定義顏色
    # RGB表示法:三個數字,每個數字的值是0-255之間,表示紅綠藍三個顏色的大小
    # 在某些系統中,之間用英文單詞表示也可以,比如red, green
    # 此處用lambda表示式
        c = lambda: random.randint(0, 255)
        self.color = '#%02x%02x%02x' % (c(), c(), c())

    def create_ball(self):
     # 用建構函式定義的變數值,在canvas上畫一個球
     # tkinter沒有畫圓形函式
     # 只有一個畫橢圓函式,畫橢圓需要定義兩個座標,
     # 在一個長方形內畫橢圓,我們只需要定義長方形左上角和右下角就好
     # 求兩個座標的方法是,已知圓心的座標,則圓心座標減去半徑能求出
     # 左上角座標,加上半徑能求出右下角座標
        x1 = self.xpos - self.radius
        y1 = self.ypos - self.radius
        x2 = self.xpos + self.radius
        y2 = self.ypos + self.radius

    # 繼續球y1, x2, y2

    # 再有兩個對角座標的前提下,可以進行畫圓
    # fill表示填充顏色
    # outline是外圍邊框顏色
        self.item = self.canvas.create_oval(x1, y1, x2, y2,fill=self.color,outline=self.color)

    def move_ball(self):
        # 移動球的時候,需要控制球的方向
        # 每次移動後,球都有一個新的座標
        self.xpos += self.xvelocity
        # 同理計算ypos
        self.ypos += self.yvelocity
        # 以下判斷是會否撞牆
        # 撞了南牆就要回頭
        # 注意撞牆的演算法判斷
        if self.xpos + self.radius >= self.scrnwidth:
            self.xvelocity = -self.xvelocity
            # 裝到了右邊牆

        if self.ypos + self.radius >= self.scrnheight:
            self.yvelocity = -self.yvelocity

        if self.ypos <=self.radius :
            self.yvelocity = abs(self.yvelocity )

        if self.xpos <= self.radius:
            self.xvelocity = abs(self.xvelocity)
            # self.xvelocity *= -1
        # 同理可以判斷撞別的牆的演算法
        # 在畫布上挪動圖畫
        self.canvas.move(self.item,self.xvelocity,self.yvelocity)



class ScreenSaver():

    # 定義屏保的類
    # 可以被啟動

    # 如何裝隨機產生的球?
    balls = list()

    def __init__(self):
        # 每次啟動球的數量隨機
        self.num_balls = random.randint(6, 20)

        self.root = Tk()
        # 取消邊框
        self.root.overrideredirect(1)

        # 任何滑鼠移動都需要取消
        self.root.bind('<Motion>', self.myquit)
        # 同理,按動任何鍵盤都需要退出屏保

        # 得到螢幕大小規格
        w, h = self.root.winfo_screenwidth(), self.root.winfo_screenheight()

        # 建立畫布,包括畫布的歸屬,規格
        self.canvas = Canvas(self.root, width=w, height=h)
        self.canvas.pack()
        print(self.canvas)
        # 在畫布上畫球
        for i in range(self.num_balls):
            ball = RandomBall(self.canvas,scrnwidth=w,scrnheight=h)
            ball.create_ball()
            self.balls.append(ball)

        self.run_screen_saver()
        self.root.mainloop()

    def run_screen_saver(self):
        for ball in self.balls:
            ball.move_ball()

        # after是200毫秒後啟動一個函式,需要啟動的函式是第二個引數
        self.canvas.after(200, self.run_screen_saver)

    def myquit(self, e):
        # 此處只是利用了事件處理機制
        # 實際上並不關心事件的型別
        # 作業:
        # 此屏保程式擴充套件成,一旦捕獲事件,則判斷屏保不退出
        # 顯示一個Button,Button上顯示事件型別,點選Button後屏保
        # 才退出
        self.root.destroy()


if __name__ == "__main__":
    # 啟動屏保
    ScreenSaver()