用Tkinter实现首个GUI
查询了一下,Python做GUI的,可以使用Tkinter库,并且这个库比较简单,容易上手,于是开干。
第一步是看去找文档:
https://docs.python.org/3/library/tk.html
感觉tutorialspoint看的东西还多一点,其他的只能自己尝试。
第一步 白板代码
先把窗口和组件画出来,再慢慢添加属性和方法
···
import tkinter as tk
if __name__ == "__main__":
root = tk.Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
root.geometry('600x360') #设置了主窗口的初始大小960x540 800x450 640x360
outputText = tk.Text(root)
outputText.grid(row=0,column=0,columnspan=7)
outputText.config(state=DISABLED)
inputLabel= tk.Label(root,text='请输入需要查询天气的城市或者指令:')
inputLabel.grid(row=1,column=0,columnspan=2)
inputEntry= tk.Entry(root)
inputEntry.grid(row=1,column=2)
inputEntry.focus_set()
queryButton= tk.Button(root,text='查询', command=queryAction)
queryButton.grid(row=1,column=3)
historyButton= tk.Button(root,text='History', command=printHelpInfo)
historyButton.grid(row=1,column=4)
quitButton= tk.Button(root,text='退出',command=quitApp)
quitButton.grid(row=1,column=5)
root.mainloop()
···
程序运行窗口:

组件对齐的方式:pack/grid/place
当时参考了下面的两篇文章,觉得grid比较简单,目前用代码形式进行书写GUI时,直接当成表格排列就可以了,于是就使用了grid进行了布局
from Tkinter import *
master = Tk()
Label(master, text="First").grid(row=0)
Label(master, text="Second").grid(row=1)
e1 = Entry(master)
e2 = Entry(master)
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
mainloop()
四个控件直接就像Excel表格一样排列,代码简单,界面整齐。
第二步 窗口正常工作
这一步复用了CH1的代码,很快就可以输出信息了。
踩过的坑:
- IndentationError: unindent does not match any outer indentation level
这个坑真是郁闷啊,是没有对齐。代码看了好多次都没什么问题,结果发现不同的编辑器对缩进是不一样的!
记得要将Tab设为4个空格!记得要将Tab设为4个空格!记得要将Tab设为4个空格!

第三步 封装
将代码封装为一个窗口Class,以后其他模块可以直接调用这个窗口。
踩过的坑:
class内所有的属性、方法和变量,前面都要加上self.,否则会提示对应的属性、方法、变量没有定义。
第一次报错时,阅读后没有发现明显错误,一运行时就提示没有找到定义。仔细想了一下,没有指定self的话,确实没有找到外部有定义该方法和函数,加入self.后解决。
TypeError: func() takes 0 positional arguments but 1 was given 方法和函数中,参数表中没有加入(self)。如果没有加的话,会有报错,提示方法和函数没有参数,但传递了一个,其实这个就是实例self。
这里有一篇文章写得很详细,可以以后再读:一篇文章让你彻底搞清楚Python中self的含义
踩坑之后,窗口终于出现鸟:
下一步再进行界面优化,以及尝试一下其他的GUI库。
附上程序代码:
gui.py:
import tkinter as tk
import datetime
class WeatherQueryFrame(tk.Frame):
city_weather={}
queryHistory=[]
def __init__(self, master=None):
super().__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
self.outputText = tk.Text(self)
#outputText.config(state=DISABLED)
self.outputText.grid(row=0,column=0,columnspan=7)
#self.outputText.insert(tk.END,city_weather['北京'])
self.inputLabel= tk.Label(self,text='请输入需要查询天气的城市或者指令:')
self.inputLabel.grid(row=1,column=0,columnspan=2)
self.inputEntry= tk.Entry(self)
self.inputEntry.grid(row=1,column=2)
self.inputEntry.bind('<Return>',self.getEnter)
self.inputEntry.insert(0,'广州')
self.inputEntry.focus_set()
self.queryButton= tk.Button(self,text='查询', command=self.queryAction)
self.queryButton.grid(row=1,column=3)
self.helpButton= tk.Button(self,text='帮助', command=self.printHelpInfo)
self.helpButton.grid(row=1,column=4)
self.historyButton= tk.Button(self,text='History', command=self.getHistory)
self.historyButton.grid(row=1,column=5)
self.quitButton= tk.Button(self,text='退出',command=self.quitApp)
self.quitButton.grid(row=1,column=6)
#初始化时读入城市天气结果
with open ('weather_info.txt', 'r', encoding='utf-8') as f:
for lines in f.readlines():
line=lines.strip().split(',')
self.city_weather[line[0]] = line[1]
def getEnter(self,event):
self.queryAction()
def printHelpInfo(self):
'''函数功能:打印帮助信息'''
helpstr='''
- 输入城市名,获取该城市的天气情况;
- 输入 ?/help,获取本帮助信息;
- 输入 h/history,获取历史查询信息;
- 输入 q/quit,退出天气查询系统。\n'''
#console打印输出
print (helpstr)
#窗口显示结果
self.outputText.insert(tk.END,helpstr+'\n')
def printErrorInfo(self):
'''函数功能:打印错误信息'''
printstr='''你输入的城市名称不存在,或者指令错误,请重新输入。
- 如果不清楚指令,可以输入?或者help, 或点击"帮助"按钮,获取帮助。
\n'''
print(printstr)
self.outputText.insert(tk.END,printstr)
def getHistory(self):
'''函数功能:打印历史查询信息,输出查询序号、时间和结果
调用格式:getHistory(history)
需要输入历史查询记录'''
history=self.queryHistory
if history:
print ()
print ('你查询过以下城市的天气情况:')
self.outputText.insert(tk.END,'\n你查询过以下城市的天气情况:\n')
for i in range(history.__len__()):
printstr=str(i+1)+' '+history[i]
print (printstr)
#窗口显示结果
self.outputText.insert(tk.END,printstr)
else:
print ('并无查询历史记录')
self.outputText.insert(tk.END,'并无查询历史记录\n')
def printWeatherInfo(self,city,history):
print (city, self.city_weather[city])
self.outputText.insert(tk.END,city + ' 的天气情况为:' + self.city_weather[city] + '\n')
#获得当前时间
now = datetime.datetime.now()
#转换为指定的格式:
dt = now.strftime("%Y-%m-%d %H:%M:%S")
historystr=dt + ' ' + city + ' 的天气情况为:' + self.city_weather[city] + '\n'
history.append(historystr)
return history
def queryAction(self):
user_input=self.inputEntry.get().lower()
if user_input=="help" or user_input=="?":
self.printHelpInfo()
self.inputEntry.delete(0, tk.END)
elif user_input=="h" or user_input=="history":
self.getHistory()
self.inputEntry.delete(0, tk.END)
elif user_input in self.city_weather:
self.queryHistory=self.printWeatherInfo(user_input,self.queryHistory)
self.inputEntry.delete(0, tk.END)
elif user_input=="q" or user_input=="quit":
self.quitApp()
else:
errorstr='你刚刚输入的 "'+user_input+ '" 有误:\n'
print (errorstr)
self.outputText.insert(tk.END,errorstr)
self.printErrorInfo()
self.inputEntry.delete(0, tk.END)
def quitApp(self):
self.getHistory()
print ('欢迎再次使用天气查询窗口,再见!')
self.master.destroy()
if __name__ == "__main__":
root = tk.Tk()
root.wm_title('天气查询窗口')
root.geometry('600x360')
main_frame=WeatherQueryFrame(root)
main_frame.mainloop()