小試 Python GUI, 以心理測驗計數練習

Python 真的是一個很棒的語言,不但語言的理念是簡單而已,還有許多好用的 library 可以用,當中官方提供的 library 已經很夠用了,而 GUI 介面是使用 Tcl/Tk 去整合。

Tcl/Tk 本來就是自成一格的腳本語言,不過 Python 肯定是發現 Tcl 是很容易做到快速開發的腳本語言,可能也是因為 Tcl 是用純命令的概念的腳本語言啦!最後 Python 把 Tcl 整合成自己的模組,也非常的 Python-like

我這幾天為了多練習 Python 一點,做了一個小小的心理測驗計數器,那當然是用 Python 內建的 Tk 比較不會那麼麻煩一點,在 Windows 下只要點兩下就會去執行了 ( 因為在安裝 Python 的時候,Python 已經會把副檔名 .py .pyw 的檔案自動找 python 來執行 ) ,在這期間,絕大部分都好好的很 OK ,唯一有一點小弟我覺得需要紀錄的就是要把事件跟觸發後的程式碼結合有點詭異

我先把我的計數器開放給大家玩好了,下次再來想要怎麼解釋 bind 元件好了

#!/usr/bin/env python3
#-*-coding: utf-8-*-
from tkinter import Tk, StringVar,Frame, Button, Label, Entry

class MainWindow(Frame):
    def __init__(self, master = None):
        Frame.__init__(self, master)
        self.pack()
        self.component = []
        self.base = 1   
        self.total = 0
        self.createWidget(4)

    def createWidget(self, num):
        Label(self, text = "選項").grid(row=self.base - 1, column = 1)
        Label(self, text = "次數").grid(row=self.base - 1, column = 2)
        Label(self, text = "每項分數").grid(row=self.base - 1, column = 3)
        Label(self, text = "分數加總").grid(row=self.base - 1, column = 4)
        Label(self, text = "+1").grid(row=self.base - 1, column = 5)
        Label(self, text = "-1").grid(row=self.base - 1, column = 6)
        for i in range(num):
            self.addCom()

        btnReset = Button(self, text = "重設", command=self.reset)
        btnAddCom = Button(self, text="增加選項")
        btnAddCom.bind("<Button-1>", lambda event, btnReset=btnReset, btnAddCom=btnAddCom:self.addRow(btnReset, btnAddCom))
        btnReset.grid(row = self.base + self.total + 1, column=3)
        btnAddCom.grid(row = self.base + self.total + 1, column=4)
    def addCom(self):
        self.component.append({"etyStr" : StringVar(),
                               "lblTimesStr":StringVar(),
                               "scoreStr":StringVar(),
                               "lblOp" : None,
                               "lblTimes" : None,
                               "ety" : None,
                               "lblScore" : None,
                               "btnPlus" : None,
                               "btnMinus" : None})
        index = self.total
        self.component[index]["etyStr"].set("0")
        self.component[index]["lblTimesStr"].set("0")
        self.component[index]["scoreStr"].set("0")
        self.component[index]["lblOp"] = Label(self, text = chr(ord("A") + self.total))
        self.component[index]["lblTimes"] = Label(self, textvariable=self.component[self.total]["lblTimesStr"])
        self.component[index]["ety"] = Entry(self,
                                             width = 5,
                                             textvariable = self.component[self.total]["etyStr"])

        self.component[index]["ety"].bind("<Leave>", lambda event, num=index : self.setEtyOver(num))
        self.component[index]["ety"].bind("<Return>", lambda event, num =index : self.setEtyOver(num))
        self.component[index]["ety"].bind("<FocusOut>", lambda event, num=index : self.setEtyOver(num))
        self.component[index]["lblScore"] = Label(self, textvariable = self.component[self.total]["scoreStr"])

        self.component[index]["btnPlus"] = Button(self, text = "+1", command = lambda index=index : self.plusOne(index))
        self.component[index]["btnMinus"] = Button(self, text = "-1", command = lambda index=index : self.minusOne(index))
        self.component[index]["lblOp"].grid(row = self.base + self.total, column = 1)

        self.component[index]["lblTimes"].grid(row = self.base + self.total, column = 2)
        self.component[index]["ety"].grid(row = self.base + self.total, column = 3)
        self.component[index]["lblScore"].grid(row = self.base + self.total, column = 4)
        self.component[index]["btnPlus"].grid(row = self.base + self.total, column = 5)
        self.component[index]["btnMinus"].grid(row = self.base + self.total, column = 6)
        self.total += 1

    def plusOne(self, num):
        self.component[num]["lblTimesStr"].set(str(int(self.component[num]["lblTimesStr"].get()) + 1))
        self.component[num]["scoreStr"].set(str(int(self.component[num]["lblTimesStr"].get()) * int(self.component[num]["etyStr"].get())))


    def minusOne(self, num):
        self.component[num]["lblTimesStr"].set(str(int(self.component[num]["lblTimesStr"].get()) - 1))
        self.component[num]["scoreStr"].set(str(int(self.component[num]["lblTimesStr"].get()) * int(self.component[num]["etyStr"].get())))

    def setEtyOver(self, num):
        if (self.component[num]["etyStr"].get()):
            self.component[num]["scoreStr"].set(str(int(self.component[num]["lblTimesStr"].get()) * int(self.component[num]["etyStr"].get())))
        else:
            self.component[num]["etyStr"].set("0")


    def reset(self):
        for i in range(self.total):
            self.component[i]["etyStr"].set("0")
            self.component[i]["lblTimesStr"].set("0")
            self.component[i]["scoreStr"].set("0")

    def addRow(self, btnReset, btnAddCom):
        self.addCom()
        btnReset.grid(row = self.base + self.total + 1, column=3)
        btnAddCom.grid(row = self.base + self.total + 1, column=4)

if __name__ == "__main__":
    root = Tk()
    root.title("心理測驗計數器")
    win = MainWindow(master = root)
    win.mainloop()