Tkinter小结 界面+快捷键设置

前言

之前写过一个关于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效果图

需要注意的是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()

结果如下:


Entry控件显示效果

关于这个输入控件常用的方法有这么几个:

  • 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) 键盘小写字母a
  • bind_all('A', eventhandler) 键盘大写字母A
  • bind_all('<Control-A>', eventhandler) Control+shift+a
  • bind_all('<Control-a>', eventhandler) Control+a
  • bind_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来写界面,但是为了以防万一,了解一下还是不错的。

这篇文章虽然算不上事无巨细,但是基本上看完之后就可以实战自己的小桌面应用了。

那么今天就先到这吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容