這個 Tkinter 很早就想學了,今天來練習看看。
教學網站:
- https://morvanzhou.github.io/tutorials/python-basic/tkinter/
- https://likegeeks.com/python-gui-examples-tkinter-tutorial/
- https://hk.saowen.com/a/e37b3703f59ae91ac7cbea9a02972238fd67d9ce10214e165de0eda7b306edd6
Create your first GUI application
First, we will import Tkinter package and create a window and set its title:
from tkinter import *
window = Tk()
window.title("Welcome to Max app")
window.mainloop()
The result will be like this:
請服用下面的 code 讓程式在 python2 & python3 都可以run:
try:
# for Python2
from Tkinter import *
import ttk
import tkMessageBox as messagebox
except ImportError:
# for Python3
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
Create a label widget
下面的範例是按了button 去修改 label 裡的值。
!/usr/bin/env python
encoding=utf-8
from tkinter import *
window = None
lbl = None
btn = None
def btn_clicked():
global lbl
lbl.config(text="Button was clicked !!")
def MainMenu(root):
global lbl
lbl = Label(root, text="Hello World", font=("Arial Bold", 50))
lbl.grid(column=0, row=0)btn = Button(root, text="Click Me", command=btn_clicked)btn.grid(column=1, row=0)
def main():
global root
root = Tk()
root.title("Welcome to Max app")
GUI = MainMenu(root)
root.geometry('450x400')
root.mainloop()
if name == "main":
main()
執行畫面:
說明: 使用 .grid() 可以把元件加入到 layout 裡, 使用 .grid_forget() 可以 hide。
Tkinter: how to show and hide Frame class:
f
will be a class, not an instance. Since self.frames
is a dictionary with the actual frames being the values, you want to loop over the values:
for f in self.frames.values():
f.grid_forget()
Get input using Entry class (Tkinter textbox)
sample code:
txt = Entry(window,width=10)
放入預設值,參考這一篇:
https://stackoverflow.max-everyday.com/2018/12/python-how-to-set-default-text-for-a-tkinter-entry-widget/
取值出來:
if entryBox.get().strip()=="":
tkMessageBox.showerror("Error", "Please enter text")
else:
print entryBox.get().strip()
Add a Checkbutton widget (Tkinter checkbox)
範例:
chk_state = BooleanVar()
chk_state.set(True) #set check state
chk = Checkbutton(window, text='Choose', variable=chk_state)
chk.grid(column=0, row=0)
Set check state of a Checkbutton
chk_state = IntVar()
chk_state.set(0) #uncheck
chk_state.set(1) #check
值得注意的是 variable 的 IntVar() or BooleanVar() 有 variable scope 的問題,所以如果沒有設對的話,會變成 always fasle.
Getting Tkinter Check Box State
var = Tkinter.IntVar()
chk = Tkinter.Checkbutton(root, text='foo', variable=var)
var.get()
如果是要 bind checkbox 事件:
def callBackFunc():
print "Oh. I'm clicked"
app = tk.Tk()
app.geometry('150x100')
chkValue = tk.BooleanVar()
chkValue.set(True)
chkExample = tk.Checkbutton(app, text='Check Box',
var=chkValue, command=callBackFunc)
Add a combobox
官方文件說明:
https://docs.python.org/3.1/library/tkinter.ttk.html
只使用 tkinter 沒有 combo 可以使用,To start using Ttk, import its module: (方案1號)
from tkinter import ttk
To override the basic Tk widgets, the import should follow the Tk import: (方案2號)
from tkinter import *
from tkinter.ttk import *
That code causes several tkinter.ttk widgets (Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, PanedWindow, Radiobutton, Scale and Scrollbar) to automatically replace the Tk widgets.
說明:這2個方案,各有優缺點,下去試看看就知道。偷懶的人建議使用方案1就好了,用方案2號優點就是畫面比較有「一致性」,主要差在 backgound 會不同。
sample code:
combo = Combobox(window)
combo['values']= (1, 2, 3, 4, 5, "Text")
combo.current(1) #set the selected item index
combo.grid(column=0, row=0)
說明: current 裡放的是 index 值,不是文字。如果要放文字可以使用 .set(“”
To get the select item, you can use the get function like this:
combo.get()
sample 2 號:
Old example from GitHub: combobox-get-selection
#!/usr/bin/env python3
import tkinter as tk
import tkinter.ttk as ttk
# --- functions ---
def on_select(event=None):
print('----------------------------')
if event: # <-- this works only with bind because `command=` doesn't send event
print("event.widget:", event.widget.get())
for i, x in enumerate(all_comboboxes):
print("all_comboboxes[%d]: %s" % (i, x.get()))
# --- main ---
root = tk.Tk()
all_comboboxes = []
cb = ttk.Combobox(root, values=("1", "2", "3", "4", "5"))
cb.set("1")
cb.pack()
cb.bind('<<ComboboxSelected>>', on_select)
all_comboboxes.append(cb)
cb = ttk.Combobox(root, values=("A", "B", "C", "D", "E"))
cb.set("A")
cb.pack()
cb.bind('<<ComboboxSelected>>', on_select)
all_comboboxes.append(cb)
b = tk.Button(root, text="Show all selections", command=on_select)
b.pack()
root.mainloop()
Add radio buttons
sample code:
rad1 = Radiobutton(window,text='First', value=1)
rad2 = Radiobutton(window,text='Second', value=2)
rad3 = Radiobutton(window,text='Third', value=3)
rad1.grid(column=0, row=0)
rad2.grid(column=1, row=0)
rad3.grid(column=2, row=0)
Get radio button value
sample code:
selected = IntVar()
rad1 = Radiobutton(window,text='First', value=1, variable=selected)
rad2 = Radiobutton(window,text='Second', value=2, variable=selected)
rad3 = Radiobutton(window,text='Third', value=3, variable=selected)
def clicked():
print(selected.get())
btn = Button(window, text="Click Me", command=clicked)
rad1.grid(column=0, row=0)
rad2.grid(column=1, row=0)
rad3.grid(column=2, row=0)
btn.grid(column=3, row=0)
Theme 佈景主題
服用下面的範例切換主題:
import tkinter
from tkinter import ttk
root = tkinter.Tk()
style = ttk.Style(root)
style.theme_use('classic')
style.configure('Test.TLabel', background= 'red')
text = ttk.Label(root, text= 'Hello', style= 'Test.TLabel')
text.grid()
root.mainloop()
內建主題有 “classic”, “default”, “aqua” 可以試看看,自己建立套用主題參考:
Apparently, the order you set the properties of the new style is important to determine if a certain property of the new style will be applied or not. For example, if I set first the background
instead of selectbackground
, then the color of selection will not be changed, but just the mini button color with the arrow (to list down the options).
I noted also that depending on the value of parent
, which I suppose is the parent stylefrom which the new style is derived, some of the new settings and properties of the new style might not be applied. For example, if I try to change the fieldbackground
property when parent
is set to aqua
, it does not work, but if parent
is set to alt
, it works. (I hope more expert users can help and contribute to improve this answer, which could be helpful also for future users of ttk
and tkinter
).
This is my solution, where I created a complete new style:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
combostyle = ttk.Style()
combostyle.theme_create('combostyle', parent='alt',
settings = {'TCombobox':
{'configure':
{'selectbackground': 'blue',
'fieldbackground': 'red',
'background': 'green'
}}}
)
# ATTENTION: this applies the new style 'combostyle' to all ttk.Combobox
combostyle.theme_use('combostyle')
# show the current styles
# print(combostyle.theme_names())
combo = ttk.Combobox(root, values=['1', '2', '3'])
combo['state'] = 'readonly'
combo.pack()
entry = tk.Entry(root)
entry.pack()
root.mainloop()
Since I am not an expert on ttk
, I was not able to apply a new theme just to a certain instance of type ttk.Combobox
, but I applied the theme to all instances of future possible ttk.Combobox
. If someone can improve this answer, I would really appreciate the gesture!
For more information on how to create and set new styles, see here or here.