前言
之前写过一个关于Python 使用easyUI创建桌面小应用的博客,虽然easyUI很实用,但是安装方面确实存在一些小小的问题。那么好吧,这次就尝试着使用自带的Tkinter好了。
另外不得不说的是,Windows环境下写界面还是用C++或者C#的好,天生自带优势,界面也更加美观。
基础知识点
下面就一些基础的空间简要的描述一下,以及它们的简单应用。
前导篇
要想写界面,就得有个载体不是。这就好比说我们要盖个房子,光有砖头,瓦块,木材是肯定不行的。我们还需要一个框架,一个承载这些组件的”平台”。
在Tkinter中,同样如此。而且创建这么一个“框架”也很简单,如下代码。
from tkinter import *
# 需要注意的是Python2.X中应该这么写
# from Tkinter import *
platform = Tk()
platform.title('标题部分')
platform.mainloop()
运行一下,结果图如下
Button篇
按钮对于一个桌面应用来说是最最常见,也必不可少的一块“砖头”了。但是在写界面的时候,我们没有见过单独一个按钮就可以跑起来的吧。就好比砖头需要盖在房子里。所以button需要依附于一个框架,也就是刚才的platform。
源码中是这样解释的。
"""Button widget."""
def __init__(self, master=None, cnf={}, **kw):
"""Construct a button widget with the parent MASTER.
STANDARD OPTIONS
activebackground, activeforeground, anchor,
background, bitmap, borderwidth, cursor,
disabledforeground, font, foreground
highlightbackground, highlightcolor,
highlightthickness, image, justify,
padx, pady, relief, repeatdelay,
repeatinterval, takefocus, text,
textvariable, underline, wraplength
WIDGET-SPECIFIC OPTIONS
command, compound, default, height,
overrelief, state, width
"""
也就是说button需要有一个parent控件。那么下面我们来看下代码。
from tkinter import *
platform = Tk()
platform.title('标题部分')
Button(platform, text='我是一个按钮').pack()
platform.mainloop()
如下
需要注意的是Button(platform, text='我是一个按钮').pack()
这行代码的pack方法,其作用是将按钮“夯”进platform,让它能显示出来。不然的话,砖头始终是砖头,成不了房子的一部分。如果没有这个方法的话,组件是不会显示的。pack方法可以传入slide参数来指定其靠齐方式。如side=LEFT啥的。
button组件除了
- text(按钮上显示的文本)
- width(宽度)
- height(按钮的高度)
- compound(依附方位)
等之外。还有一个比较重要的属性,那就是command。这就是响应按钮被点击的时候的回调函数。说白了就是 点击按钮之后会触发什么响应事件。下面我们来看个小小的例子。
这样就可以啦。也许你会想,为啥callback没有参数啊,我想在点击按钮的时候传一个参数来改变一些行为怎么办呢?
关于这块,我也查看了一下官方文档,发现确实没有相关的api可以被直接的调用。但是有下面这种间接的方式实现。
from tkinter import *
def callback():
global button
print('按钮被点击了!')
# 动态修改按钮的属性
button['text'] = '修改后的按钮文本'
button['width']=28
button['height'] = 16
button['compound'] = 'center'
# 甚至还可以动态修改按钮绑定的回调处理函数
button['command'] = callback2
def callback2():
print('动态修改按钮的回调函数!')
platform = Tk()
platform.title('标题部分')
button = Button(platform, text='我是一个按钮', command=callback)
button.pack()
platform.mainloop()
结果如下
Label篇
标签,同样是很简单的一个控件。使用方法和button控件一致。
更多属性设置可以参考官方文档,或者直接点进去源码查看。
Entry篇
没有输入控件的界面是不完整的界面,下面浅谈一下entry控件的基本使用。
from tkinter import *
platform = Tk()
platform.title('标题部分')
Label(platform, text='Username:').pack(side=LEFT)
Entry(platform, bg='black', fg='white', width=12).pack(side=LEFT)
platform.mainloop()
结果如下:
关于这个输入控件常用的方法有这么几个:
- get() 获取当前这个空间的字符内容。
- select_clear() 清空当前被选择的输入控件的内容,如果当前输入控件没有获得鼠标焦点,则不会有什么影响。
- … …
其他控件
其他的控件的使用方式都是类似的,学会了前几个,相信对于后面的也不是什么难事了。
有兴趣的话可以参考官方的帮助文档。
https://docs.python.org/2/library/tkinter.html
事件篇
下面介绍一下关于界面的事件处理篇。因为我在一开始使用的时候没能成功,也是从各处搜索才找到答案。因此介绍一下,也为了让更多的人少走弯路。
我自己的理解是Tkinter把关于界面的所有的事件都封装成了一个对象,我们可以方便的从这个对象中获取到已经发生的事件,然后只需要针对不同的事件作出相应的处理即可。
这里简单的介绍一下对于键盘事件的处理吧。
一般来说只需要一个下面一个方法:
bind_all(哪个键, 对应的处理函数)
下面针对一个小例子进行讲解。
from tkinter import *
root = Tk()
root.title("窗口测试")
def eventhandler(event):
if event.keysym == 'Left':
print('按下了方向键左键')
elif event.keysym == 'Right':
print('按下了方向键右键!')
btn = Button(root, text='button')
btn.bind_all('<KeyPress>', eventhandler)
btn.pack()
root.mainloop()
运行的时候我们按下键盘上的方向键左键,就会打印对应的处理内容。右键类似。
按下了方向键右键!
按下了方向键左键
按下了方向键左键
按下了方向键右键!
按下了方向键左键
按下了方向键右键!
按下了方向键右键!
按下了方向键右键!
按下了方向键右键!
按下了方向键左键
按下了方向键左键
按下了方向键左键
关于bind_all方法,第一个参数对应的内容很多。我在这里尽可能把常用的罗列一下,免得大家再去单独搜索。
bind_all('<KeyPress-Up>', eventhandler)
键盘方向键上键bind_all('<KeyPress-Down>', eventhandler)
键盘方向键下键bind_all('<KeyPress-Left>', eventhandler)
键盘方向键左键bind_all('<KeyPress-Right>', eventhandler)
键盘方向键右键bind_all('<KeyPress>', eventhandler)
键盘键位通用处理bind_all('<Enter>', eventhandler)
按下Enter键bind_all('a', eventhandler)
键盘小写字母abind_all('A', eventhandler)
键盘大写字母Abind_all('<Control-A>', eventhandler)
Control+shift+abind_all('<Control-a>', eventhandler)
Control+abind_all('<Control-Alt-b>', eventhandler)
Control+Alt+b相似的,Tkinter支持下面这些按键。但是需要知道的是不支持
Control—Alt
Cancel/Break/BackSpace/Tab/Return/Sift_L/Shift_R/Control_L/Control_R/Alt_L/Alt_R/Pause
Caps_Loack/Escape/Prior(Page Up)/Next(Page Down)/End/Home/Left/Up/Right/Down/Print/Insert/Delete/
F1-12/Num_Lock/Scroll_Lock
小应用
学完了上面的这些控件及其需要注意的地方,写一个简单的桌面小应用就足够了。
下面以一个小例子来收尾,功能是爬取糗事百科上的段子信息。
# coding: utf8
# @Author: 郭 璞
# @File: Main.py
# @Time: 2017/4/21
# @Contact: 1064319632@qq.com
# @blog: http://blog.csdn.net/marksinoberg
# @Description: 糗事百科 带界面版本
# 网络操作相关
import requests
from bs4 import BeautifulSoup
# 创建一个接口,返回json串
import json
# 创建GUI使用
from tkinter import *
def show(url):
headers = {
'host':'www.qiushibaike.com',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36"
}
response = requests.get(url=url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
response = None
containers = soup.find_all('div', {'class': 'article block untagged mb15'})
result = []
for container in containers:
# 'div', {'class': 'author clearfix'}
try:
# 对于非匿名用户可正常获取
username = container.find('div', {'class': 'author clearfix'}).find_all('a')[1].find('h2').get_text()
except:
# 对于匿名用户,HTML标签特殊处理
username = container.find('div', {'class': 'author clearfix'}).find_all('span')[1].get_text()
# print(username)
content = container.find('a', {'class': 'contentHerf'}).find('div', {'class': 'content'}).find('span').get_text()
# print(content)
try:
hotcommentuser = container.find('a', {'class': 'indexGodCmt'}).find('div', {'class': 'cmtMain'}).find('span', {'class': 'cmt-name'}).get_text()
hotcommentcontent = container.find('a', {'class': 'indexGodCmt'}).find('div', {'class': 'cmtMain'}).find('div', {'class': 'main-text'}).get_text()
# 去除大块大块的空格,尽量去掉换行标记。
hotcomment = str(hotcommentuser).strip(' ').strip('\n').strip('\r') + str(hotcommentcontent).strip(' ').strip('\n').strip('\r')
except:
# 奇奇怪怪的问题。
hotcomment = "热评人: 无, 热评内容: 无"
# 封装糗事及评论
item = {
'username': username,
'content': content,
'hotcomment': hotcomment
}
result.append(item)
# 以列表的形式返回数据,以备调用
return result
def main(page=3, outputpath='./qiubai.txt'):
"""
想要获取几页的数据啊
:param page:
:return:
"""
total = []
for index in range(page):
url = 'http://www.qiushibaike.com/8hr/page/{}/'.format(index+1)
result = show(url=url)
total.extend(result)
# 待会可以删除,转为json格式罢了
total = json.dumps(total)
# 写入一个文件待用
with open(outputpath, 'a', encoding='utf8') as f:
for item in total:
f.write(str(item)+"\n")
f.close()
print('糗事百科笑话全部入库,详情请查看{}文件'.format(outputpath))
def getdata(page=3):
"""
实时获取糗事百科段子,默认页数为3,可进行外部控制。但是范围是1-35.
:param page:
:return:
"""
if page <1 or page > 35:
raise Exception('您输入的页码超过了官网限制!请保持在1-35之间!')
else:
total = []
for index in range(page):
url = 'http://www.qiushibaike.com/8hr/page/{}/'.format(index + 1)
result = show(url=url)
total.extend(result)
# 返回获取到的段子字典,以供外部调用!
return total
def ui(title="糗事百科段子--桌面版"):
global label
root = Tk()
root.title(title)
label = Label(root, text="系统正在努力为您拉取段子\n请稍后... ...", height=36, compound='center')
label['text'] = "软件使用方法:\n- 按方向键←或者↑查看上一条段子\n- 按方向键↓或者→查看下一条段子。\n系统正在努力为您拉取段子\n请稍后... ..."
label.pack()
root.bind_all('<KeyPress>', eventhandler)
root.mainloop()
def eventhandler(event):
global index
total = getdata(page=3)
index = (index+len(total))%len(total)
if event.keysym == 'Up' or event.keysym == "Left":
index -= 1
print('前一个')
elif event.keysym == 'Down' or event.keysym == 'Right':
index += 1
print('下一个')
content = "发帖人:\t{}\n".format(total[index]['username'])+"\n\t{}\n".format(total[index]['content'])+"热评:{}\n".format(total[index]['hotcomment'])
label['text'] = content
if __name__ == '__main__':
content = ""
index = 0
label = None
ui(title='我的糗事百科桌面版')
使用方式: 界面运行按下键盘的方向键即可操作。↑←代表查看上一个段子。↓→代表查看下一个段子。
运行效果如下面的GIF图。 糗事百科简易粗糙桌面版本。
总结
一般来说我们不会用Python来写界面,但是为了以防万一,了解一下还是不错的。
这篇文章虽然算不上事无巨细,但是基本上看完之后就可以实战自己的小桌面应用了。
那么今天就先到这吧。