使用 Python TKinetr 去擷取 空氣品質指標(AQI) 的資料
import tkinter as tk
from tkinter import ttk
import requests
class AirQualityApp:
def __init__(self, root):
self.root = root
self.root.title("台灣空氣品質監測")
self.root.geometry("1200x700") # 調整視窗大小以容納更多欄位
self.api_url = "https://data.moenv.gov.tw/api/v2/aqx_p_432?api_key=221974dd-667c-4243-b308-61b60bc29986&limit=1000&sort=ImportDate%20desc&format=JSON"
# 定義您想顯示的欄位及其對應的 API 鍵名
# 關鍵修正:將 "site_name" 改為 "sitename"
self.display_columns_map = {
"測站名稱": "sitename", # <-- 這裡從 "site_name" 改為 "sitename"
"縣市": "county",
"空氣品質指標(AQI)": "aqi",
"空氣污染指標物": "pollutant",
"狀態": "status",
"二氧化硫(ppb)": "so2",
"一氧化碳(ppm)": "co",
"臭氧(ppb)": "o3",
"臭氧8小時移動平均(ppb)": "o3_8hr",
"懸浮微粒(μg/m3)": "pm10",
"細懸浮微粒(μg/m3)": "pm25",
"二氧化氮(ppb)": "no2",
"氮氧化物(ppb)": "nox",
"測站編號": "siteid",
"發布時間": "publishtime"
}
self.create_widgets()
self.fetch_and_display_data()
def create_widgets(self):
# 控制按鈕區塊
control_frame = tk.Frame(self.root)
control_frame.pack(pady=10)
refresh_button = tk.Button(control_frame, text="重新整理資料", command=self.fetch_and_display_data)
refresh_button.pack(side=tk.LEFT, padx=5)
# Treeview 顯示資料
self.tree = ttk.Treeview(self.root, show="headings")
self.tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 設定 Treeview 的 columns
# 這裡使用 display_columns_map 的 keys() 作為 Treeview 的欄位標題
self.tree["columns"] = list(self.display_columns_map.keys())
# 設定每個欄位的標題和屬性
for col_name in self.display_columns_map.keys():
self.tree.heading(col_name, text=col_name, command=lambda c=col_name: self.sort_treeview(self.tree, c, False))
self.tree.column(col_name, width=120, anchor='center') # 調整預設欄寬
# 捲軸
vsb = ttk.Scrollbar(self.tree, orient="vertical", command=self.tree.yview)
vsb.pack(side='right', fill='y')
self.tree.configure(yscrollcommand=vsb.set)
hsb = ttk.Scrollbar(self.tree, orient="horizontal", command=self.tree.xview)
hsb.pack(side='bottom', fill='x')
self.tree.configure(xscrollcommand=hsb.set)
def fetch_and_display_data(self):
try:
response = requests.get(self.api_url)
response.raise_for_status() # 檢查 HTTP 錯誤
data = response.json()
records = data.get("records", [])
# 根據測站名稱 (sitename) 排序資料
# 這裡的 "sitename" 是 API 返回的實際鍵名
records.sort(key=lambda x: x.get("sitename", "")) # <-- 這裡從 "site_name" 改為 "sitename"
self.clear_treeview()
if not records:
self.tree.heading("#0", text="無資料")
return
# 插入新資料
for record in records:
# 遍歷 display_columns_map 的值(即 API 的鍵名),並依序從 record 中取值
row_values = [record.get(api_key, "") for api_key in self.display_columns_map.values()]
self.tree.insert("", "end", values=row_values)
except requests.exceptions.RequestException as e:
self.clear_treeview()
self.tree.heading("#0", text=f"錯誤: 無法取得資料 - {e}")
except ValueError as e:
self.clear_treeview()
self.tree.heading("#0", text=f"錯誤: 資料解析失敗 - {e}")
except Exception as e:
self.clear_treeview()
self.tree.heading("#0", text=f"發生未知錯誤: {e}")
def clear_treeview(self):
# 清除現有資料
for item in self.tree.get_children():
self.tree.delete(item)
self.tree.heading("#0", text="") # 清除預設標題
# 排序功能 (可選,但很有用)
def sort_treeview(self, tree, col, reverse):
# 找到點擊的欄位在 Treeview 欄位列表中的索引
try:
col_index = list(self.display_columns_map.keys()).index(col)
except ValueError:
# 如果欄位名稱不在 display_columns_map 的 keys 中,則不執行排序
return
l = []
for item_id in tree.get_children(''):
item_values = tree.item(item_id, 'values')
if col_index < len(item_values):
value = item_values[col_index]
else:
value = "" # 如果資料不完整,則視為空值
l.append((value, item_id))
# 嘗試將數值型資料轉換為 float 以進行正確排序
def sort_key_func(item):
val = item[0]
if isinstance(val, str) and val.replace('.', '', 1).isdigit() and val != '':
try:
return float(val)
except ValueError:
return val # 無法轉換為數字時,按字串排序
return val
l.sort(key=sort_key_func, reverse=reverse)
# 重新排列項目
for index, (val, k) in enumerate(l):
tree.move(k, '', index)
# 翻轉下次排序的順序
tree.heading(col, command=lambda: self.sort_treeview(tree, col, not reverse))
if __name__ == "__main__":
root = tk.Tk()
app = AirQualityApp(root)
root.mainloop()


沒有留言:
張貼留言