# 綜合練習
## 一行程式碼可以做甚麼
```
'\n'.join([''.join([('\x4c\x6f\x76\x65\u2665'[(x-y) % len('\x4c\x6f\x76\x65\u2665')] if ((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 <= 0 else ' ') for x in range(-30, 30)])for y in range(30, -30, -1)])
```
讓使用者輸入字串後,變化愛心的內容:
```
import time
user_input = input('請輸入想顯ˋ的字串: ')
datas = user_input.split() # 以空白字元來切割字串並回傳一個list
# print(datas)
# datas = ['Hello ', 'world', 'I ', 'am ', 'Aaron ', 'test ', 'momo ']
for i in datas:
print('\n'.join([''.join([(i[(x-y) % len(i)] if ((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 <= 0 else ' ') for x in range(-30, 30)])for y in range(30, -30, -1)]))
time.sleep(1)
```
# Python GUI使用tkinter模組
## BMI計算機
> tkinter為Python的一個內建模組
### 建立一個空白視窗
```
import tkinter as tk
window = tk.Tk() # 建立一個視窗存到window變數
window.title('BMI app')
window.geometry('640x480')
window.configure(background='purple') # 改變視窗被景色(purple=紫色)
window.mainloop() # 啟動視窗迴圈來等待使用者操作,必須放在最後一行
```
### 加上一個標籤(Label)
```
header_label = tk.Label(window, text='BMI計算機', font='微軟正黑體 30', bg='purple', fg='yellow') # 建立Label物件並存放到header_label變數, font=設定字型跟文字大小
header_label.pack(pady=10) # 將Label顯示出來,pady=上下的間距
```
### 加上輸入體重跟身高的標籤(Label)+輸入框(Entry)
```
# 建立體重輸入欄位跟提示訊息
weight_frame = tk.Frame(window, bg='purple')
weight_frame.pack()
weight_label = tk.Label(weight_frame, text='體重(kg)', font='微軟正黑體 20', bg='purple')
weight_label.pack(side=tk.LEFT)
weight_entry = tk.Entry(weight_frame, font='微軟正黑體 20', bg='purple')
weight_entry.pack(side=tk.LEFT)
# 建立身高輸入欄位跟提示訊息
height_frame = tk.Frame(window, bg='purple')
height_frame.pack()
height_label = tk.Label(height_frame, text='身高(cm)', font='微軟正黑體 20', bg='purple')
height_label.pack(side=tk.LEFT)
height_entry = tk.Entry(height_frame, font='微軟正黑體 20', bg='purple')
height_entry.pack(side=tk.LEFT, pady=10)
```
> 我們使用Frame來包圍標籤(Label)跟輸入框(Entry)
### 建立顯示結果的Label
```
# 建立顯示結果的Label
result_label = tk.Label(window, text='', font='微軟正黑體 20', bg='purple')
result_label.pack()
```
### 建立按鈕
```
def calculate_bmi():
# tk.messagebox.showinfo('標題', '計算BMI')
w = weight_entry.get()
h = height_entry.get()
result_label.configure(text='您輸入身高為{}公分, 體重為{}公斤'.format(h, w))
# 建立按鈕
calculate_btn = tk.Button(window, text='計算', font='微軟正黑體 20', command=calculate_bmi)
calculate_btn.pack()
```
> 透過command參數,使用者在點擊按鈕後會觸發執行command設定的函示。
### 完整程式碼
```
# -*- coding: utf-8 -*-
import tkinter as tk
def calculate_bmi():
if height_entry.get() == '':
tk.messagebox.showerror('錯誤', '身高欄位不能為空')
return
if weight_entry.get() == '':
tk.messagebox.showerror('錯誤', '體重欄位不能為空')
return
w = float(weight_entry.get()) # 取得使用者輸入的體重
h = float(height_entry.get()) / 100 # 取得使用者輸入的身高並轉為公尺
if 0.2 > h or h > 2.5:
tk.messagebox.showerror('錯誤', '身高需介於20~250公分之間')
return
if 5 > w or w > 200:
tk.messagebox.showerror('錯誤', '體重需介於5~200公斤之間')
return
# BMI計算公式: BMI=體重/身高(公尺)的平方
bmi = round(w / (h ** 2), 2) # 或 int(w / (h ** 2) * 100) / 100
des = '' # 建議
if bmi < 18.5:
des = '體重過輕'
elif 24 <= bmi < 27:
des = '有點過重, 該運動了'
elif 27 <= bmi < 30:
des = '輕度肥胖, 請多運動'
elif 30 <= bmi < 35:
des = '中度肥胖, 很需要運動'
elif bmi >= 35:
des = '重度肥胖, 呃~'
else:
des = '很標準'
result_label.configure(text='您的BMI為{}, {}'.format(bmi, des))
window = tk.Tk() # 建立一個視窗存到window變數
window.title('BMI app')
window.geometry('640x480')
window.configure(background='purple') # 改變視窗被景色(purple=紫色)
# t = '\n'.join([''.join([('\x4c\x6f\x76\x65\u2665'[(x-y) % len('\x4c\x6f\x76\x65\u2665')] if ((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 <= 0 else ' ') for x in range(-30, 30)])for y in range(30, -30, -1)])
header_label = tk.Label(window, text='BMI計算機', font='微軟正黑體 30', bg='purple', fg='yellow') # 建立Label物件並存放到header_label變數, font=設定字型跟文字大小
header_label.pack(pady=10) # 將Label顯示出來,pady=上下的間距
# 建立身高輸入欄位跟提示訊息
height_frame = tk.Frame(window, bg='purple', width=500)
height_frame.pack()
height_label = tk.Label(height_frame, text='身高: ', font='微軟正黑體 20', bg='purple', fg='white')
height_label.pack(side=tk.LEFT)
height_entry = tk.Entry(height_frame, font='微軟正黑體 20', bg='purple', width=10)
height_entry.pack(side=tk.LEFT, pady=10)
height_label2 = tk.Label(height_frame, text='(cm)', font='Courier 20', bg='purple', fg='white')
height_label2.pack(side=tk.LEFT)
# 建立體重輸入欄位跟提示訊息
weight_frame = tk.Frame(window, bg='purple')
weight_frame.pack()
weight_label = tk.Label(weight_frame, text='體重: ', font='微軟正黑體 20', bg='purple', fg='white')
weight_label.pack(side=tk.LEFT)
weight_entry = tk.Entry(weight_frame, font='微軟正黑體 20', bg='purple', width=10)
weight_entry.pack(side=tk.LEFT)
weight_label2 = tk.Label(weight_frame, text='(kg)', font='Courier 20', bg='purple', fg='white')
weight_label2.pack(side=tk.LEFT)
# 建立顯示結果的Label
result_label = tk.Label(window, text='', font='微軟正黑體 20', bg='purple', fg='pink')
result_label.pack(pady=10)
# 建立按鈕
calculate_btn = tk.Button(window, text='計算', font='微軟正黑體 20', bg='pink', command=calculate_bmi)
calculate_btn.pack(side=tk.BOTTOM, pady=10)
window.mainloop() # 啟動視窗迴圈來等待使用者操作,必須放在最後一行
```
### 參考資料
- [Tkinter較完整的網路教學](https://www.itread01.com/content/1547705544.html)
- [BMI介紹](https://health99.hpa.gov.tw/OnlinkHealth/Onlink_BMI.aspx)
## 猜拳遊戲
```
import tkinter as tk
from PIL import Image, ImageTk
import random
SCISSORS = 0
ROCK = 1
PAPER = 2
# 玩家出了剪刀
def scissors():
pc = random.randint(0, 2) # 電腦出拳
# 先將電腦出拳顯示在畫面上給玩家看
if pc == SCISSORS:
pc_label.configure(text='電腦出了: 剪刀')
elif pc == ROCK:
pc_label.configure(text='電腦出了: 石頭')
else:
pc_label.configure(text='電腦出了: 布')
# 比輸贏
if pc == SCISSORS:
result_label.configure(text='遊戲結果: 平手')
elif pc == ROCK:
result_label.configure(text='遊戲結果: 你輸了')
else:
result_label.configure(text='遊戲結果: 你贏了')
# 玩家出了石頭
def rock():
pc = random.randint(0, 2) # 電腦出拳
# 先將電腦出拳顯示在畫面上給玩家看
if pc == SCISSORS:
pc_label.configure(text='電腦出了: 剪刀')
elif pc == ROCK:
pc_label.configure(text='電腦出了: 石頭')
else:
pc_label.configure(text='電腦出了: 布')
# 比輸贏
if pc == SCISSORS:
result_label.configure(text='遊戲結果: 你贏了')
elif pc == ROCK:
result_label.configure(text='遊戲結果: 平手')
else:
result_label.configure(text='遊戲結果: 你輸了')
# 玩家出了布
def paper():
pc = random.randint(0, 2) # 電腦出拳
# 先將電腦出拳顯示在畫面上給玩家看
if pc == SCISSORS:
pc_label.configure(text='電腦出了: 剪刀')
elif pc == ROCK:
pc_label.configure(text='電腦出了: 石頭')
else:
pc_label.configure(text='電腦出了: 布')
# 比輸贏
if pc == SCISSORS:
result_label.configure(text='遊戲結果: 你輸了')
elif pc == ROCK:
result_label.configure(text='遊戲結果: 你贏了')
else:
result_label.configure(text='遊戲結果: 平手')
window = tk.Tk() # 建立一個視窗存到window變數
window.title('猜拳遊戲')
window.geometry('640x480')
window.configure(bg='dark red') # 改變視窗被景色(purple=紫色)
title = tk.Label(window, text='猜拳遊戲', font='微軟正黑體 30', fg='white', bg='dark red')
title.pack(pady=10)
frame = tk.Frame(window, bg='dark red')
frame.pack(pady=10)
# 載入遊戲圖片
img_scissors = Image.open('剪刀.jpg') # 開啟並載入圖片檔
photo_scissors = ImageTk.PhotoImage(img_scissors) # 解碼jpg檔
img_rock = Image.open('石頭.jpg') # 開啟並載入圖片檔
photo_rock = ImageTk.PhotoImage(img_rock) # 解碼jpg檔
img_paper = Image.open('布.jpg') # 開啟並載入圖片檔
photo_paper = ImageTk.PhotoImage(img_paper) # 解碼jpg檔
scissors_btn = tk.Button(frame, text='剪刀', image=photo_scissors, bg='dark red', command=scissors)
scissors_btn.pack(side=tk.LEFT, padx=10)
rock_btn = tk.Button(frame, text='石頭', image=photo_rock, bg='dark red', command=rock)
rock_btn.pack(side=tk.LEFT, padx=10)
paper_btn = tk.Button(frame, text='布', image=photo_paper, bg='dark red', command=paper)
paper_btn.pack(side=tk.LEFT, padx=10)
# 顯示遊戲提示Label
prompt_label = tk.Label(window, font='微軟正黑體 20', text='請點擊按鈕來遊玩', fg='yellow', bg='dark red')
prompt_label.pack(pady=15)
# 顯示電腦出了甚麼Label
pc_label = tk.Label(window, font='微軟正黑體 30', fg='white', bg='dark red')
pc_label.pack(pady=15)
# 顯示遊戲結果Label
result_label = tk.Label(window, font='微軟正黑體 30', fg='white', bg='dark red')
result_label.pack(pady=15)
window.mainloop()
```


