【Python入门基础】基于tkinter模块的GUI(一)——TK

图形用户界面

  • GUI是图形用户界面的缩写,Python默认的GUI开发模块是tkinter,是基于Tk的,Tk是一个工具包,提供了跨平台的GUI控件。但Tk并不是最新最好的选择,也没有功能特别强大的GUI控件,事实上,开发GUI应用并不是Python最擅长的工作,如果真的需要使用Python开发GUI应用,wxPython、PyQt、PyGTK等模块都是不错的选择。
  • 基本上使用tkinter来开发GUI应用需要5个步骤:
  1. 导入tkinter模块中我们需要的;
  2. 创建一个顶层窗口对象并用它来承载整个GUI应用;
  3. 在顶层窗口对象上添加GUI组件;
  4. 通过代码将这些GUI组件的功能组织起来;
  5. 进入主事件循环(main loop)
  • GUI应用通常是事件驱动式的,之所以要进入主事件循环是要监听鼠标、键盘等各种时间的发生并执行对应的代码对事件进行处理,因为事件会持续地发生,所以需要在主循环中等待事件发生。另外,Tk为控件地摆放提供了三种布局管理器,通过布局管理器可以对控件进行定位,这三种布局管理器分别是:Placer(开发者提供控件地大小和摆放的位置)、Packer(自动将控件填充到合适的位置)、和Grid(基于网格坐标来摆放控件)。

简单实现按钮Button

import tkinter as tk

class APP:
    def __init__(self,master):
        frame = tk.Frame(master)
        frame.pack(side = tk.LEFT,padx=10,pady=10)
        self.hi_there = tk.Button(frame,text='打招呼',bg='black',fg='white',command=self.say_hi)
        self.hi_there.pack()
    def say_hi(self):
        print('hi')
root = tk.Tk()
app = APP(root)
root.mainloop()

简单实现标签Label

 

from tkinter import *
root = Tk()
def callback():
    var.set('冲')
frame1 = Frame(root)
frame2 = Frame(root)

# 设置字符变量
var = StringVar()
var.set('每日力扣')
textLabel = Label(frame1,
                  textvariable=var,
                  justify=LEFT,
                  padx=10)
textLabel.pack(side=LEFT)
photo = PhotoImage(file='leetcode.gif')
imgLabel = Label(frame1,image=photo)
imgLabel.pack(side=RIGHT)
theButton = Button(frame2,text='加油',command=callback)
theButton.pack()

frame1.pack(padx=10,pady=10)
frame2.pack(padx=10,pady=10)
root.mainloop()

eg.小窗口

import tkinter
import tkinter.messagebox


def main():
    flag = True

    # 修改标签上的文字
    def change_label_text():
        nonlocal flag
        flag = not flag
        color, msg = ('red', '武汉加油')\
            if flag else ('blue', '期待春暖花开')
        label.config(text=msg, fg=color)

    # 确认退出
    def confirm_to_quit():
        if tkinter.messagebox.askokcancel('温馨提示', '确定要退出吗?'):
            top.quit()

    # 创建顶层窗口
    top = tkinter.Tk()
    # 设置窗口大小
    top.geometry('240x160')
    # 设置窗口标题
    top.title('中国加油')
    # 创建标签对象
    label = tkinter.Label(top, text='武汉加油', font='Arial -32', fg='red')
    label.pack(expand=1)
    # 创建一个装按钮的容器
    panel = tkinter.Frame(top)
    # 创建按钮对象
    button1 = tkinter.Button(panel, text='修改', command=change_label_text)
    button1.pack(side='left')
    button2 = tkinter.Button(panel, text='退出', command=confirm_to_quit)
    button2.pack(side='right')
    panel.pack(side='bottom')
    # 开启主事件循环
    tkinter.mainloop()


if __name__ == '__main__':
    main()

运行结果:

说明:‘nonlocal’是Python3中的关键字,Python2.x中没有这个关键字。在Python2.x中闭包只能读取外部函数的变量,而不能改变变量值,而定义位全局变量‘global’很难控制,此时引入了‘nonlocal’,只要在闭包内用nonlocal声明变量,就可以让解释器在外层函数中查找变量名了。来自《Python的闭包和nonlocal》。

 选择框

多选

from tkinter import *
root = Tk()
beauty = ['西施','貂蝉','王昭君','杨玉环']
v = []
for woman in beauty:
    v.append(IntVar())
    b = Checkbutton(root,text=woman,variable=v[-1])
    b.pack(anchor=W)
mainloop()

单选

from tkinter import *
root = Tk()
v = IntVar()
Radiobutton(root,text='One',variable=v,value=1).pack(anchor=W)
Radiobutton(root,text='Two',variable=v,value=2).pack(anchor=W)
Radiobutton(root,text='Three',variable=v,value=3).pack(anchor=W)
mainloop()

from tkinter import *
root = Tk()
languages =[
    ('python',1),
    ('perl',2),
    ('ruby',3),
    ('lua',4)
]
v = IntVar()
v.set(1)
for lan,num in languages:
    b = Radiobutton(root,text=lan,variable=v,value=num,indicatoron=False)
    b.pack(fill=X)
mainloop()

from tkinter import *
root = Tk()
group = LabelFrame(root,text='最好的脚本语言是?',padx=5,pady=5)
group.pack(padx=10,pady=10)
languages =[
    ('python',1),
    ('perl',2),
    ('ruby',3),
    ('lua',4)
]
v = IntVar()
for lan,num in languages:
    b = Radiobutton(group,text=lan,variable=v,value=num)
    b.pack(anchor=W)
mainloop()

 

账号密码界面

from tkinter import *
root = Tk()
Label(root,text='账号:').grid(row=0,column=0)
Label(root,text='密码:').grid(row=1,column=0)

v1 = StringVar()
v2 = StringVar()

e1 = Entry(root,textvariable=v1)
e2 = Entry(root,textvariable=v2,show='*')

e1.grid(row=0,column=1,padx=10,pady=10)
e2.grid(row=1,column=1,padx=10,pady=10)

def show():
    print('账号:%s'%e1.get())
    print('密码:%s' % e2.get())

Button(root,text='芝麻开门',width=10,command=show).grid(row=3,column=0,sticky=W,padx=10,pady=5)
Button(root,text='退出',width=10,command=root.quit).grid(row=3,column=1,sticky=E,padx=10,pady=5)
mainloop()

内容验证

from tkinter import *
master = Tk()
v = StringVar()
def test1():
    if v.get() == 'yes':
        print('True')
        return True
    else:
        print(False)
        e1.delete(0,END)
        return False
def test2():
    print('test2')
    return True
"""
'''
开启Entry对输入文本验证功能。
1、实现该功能,需要通过设置validate、validatecommand和invalidcommand三个选项。 
2、启用验证的开关是validate选项,该选项可以设置以下的值:
    focus:当entry组件获得或者失去焦点的时候验证 
    focusin:当entry组件获得焦点的时候验证 
    focusout:当entry组件失去焦点的时候验证 
    key:当输入框被编辑的时候验证 
    all:当出现上面任何一种情况时候验证 
    none:关闭验证功能。默认设置为该选项
3、validatecommand选项指定一个验证函数,该函数只能返回True或者False表示验证结果,一般情况下验证函数只需要知道输入框中的内容即可,
可以通过Entry组件的get()方法来获得该字符串。
4、invalidcommand选项指定的函数只有在validatecommand的返回值为False的时候才被调用。
'''
'''
validatecommand选项指定一个验证函数,该函数只能返回True或者False表示验证结果
invalidcommand选项指定的函数只有在validatecommand的返回值为False的时候才被调用。
"""
e1 = Entry(master,textvariable=v,validate='focusout',validatecommand=test1,invalidcommand=test2)
e2 = Entry(master)
e1.pack(padx=10,pady=10)
e2.pack(padx=10,pady=10)

mainloop()

加法计算器

from tkinter import *
master = Tk()

frame = Frame(master)
frame.pack(padx=10,pady=10)

v1 = StringVar()
v2 = StringVar()
v3 = StringVar()

def test(content):
    return content.isdigit()

testCMD = master.register(test)
e1 = Entry(frame,width=10,textvariable=v1,validate='key',
           validatecommand=(testCMD,'%P')
           ).grid(row=0,column=0)
Label(frame,text='+').grid(row=0,column=1)
e2 = Entry(frame,width=10,textvariable=v2,validate='key',
           validatecommand=(testCMD,'%P')
           ).grid(row=0,column=2)
Label(frame,text='=').grid(row=0,column=3)
# 默认为 state=NORMAL, 文框状态,分为只读和可写,值为:normal/disabled
e3 = Entry(frame,width=10,textvariable=v3,state='readonly').grid(
    row=0,column=4
)
def calc():
    result = int(v1.get()) + int(v2.get())
    v3.set(str(result))
Button(frame,text="计算结果",command=calc).grid(row=1,column=2,pady=5)
mainloop()

Listbox

Listbox组件根据selectmode选项提供了四种不同的选择模式:SINGLE(单选)、BROWSE(也是单选,但拖动鼠标或者通过方向键可以直接改变选项)、MULTIPLE(多选)和EXTENDED(也是多选,但需要同时按住Shift或者Ctrl或者拖拽鼠标实现)。默认BROWSE。

from tkinter import *
master = Tk()

theLB = Listbox(master,selectmode=SINGLE)
theLB.pack()

for item in ['数学','语文','英语','物理','化学','生物']:
    theLB.insert(END,item)

theButton = Button(master,text='删除',command=lambda x=theLB:x.delete(ACTIVE))
theButton.pack()
mainloop()

为了在某个组件上安装垂直滚动条,需要做两件事:

  1. 设置该组件的yscrollbarcommand选项为Scrollbar组件的set()方法;
  2. 设置Scrollbar组件的command选项为该组件的yview()方法。
from tkinter import *
master = Tk()

sb = Scrollbar(master)
sb.pack(side=RIGHT,fill=Y)

lb = Listbox(master,yscrollcommand=sb.set)

for i in range(1000):
    lb.insert(END,i)
lb.pack(side=LEFT,fill=BOTH)

sb.config(command=lb.yview)
mainloop()

from tkinter import *
master = Tk()

s1 = Scale(master,from_=0,to=42)
s1.pack()

s2 = Scale(master,from_=0,to=200,orient=HORIZONTAL)
s2.pack()

def show():
    print(s1.get(),s2.get())
Button(master,text='获取位置',command=show).pack()

mainloop()

精准刻度

from tkinter import *
master = Tk()

Scale(master,from_=0,to=42,tickinterval=5,resolution=5,length=200).pack()

Scale(master,from_=0,to=200,tickinterval=10,orient=HORIZONTAL,
      length=600).pack()

mainloop()

text中插入按钮和图片

from tkinter import *
master = Tk()

text=Text(master,width=30,height=5)
text.pack()
text.insert(INSERT,'我是一名保安')
text.insert(END,'爱吃小熊饼干')
def show():
    print('点击完成')

b1 = Button(text,text='点击',command=show)
text.window_create(INSERT,window=b1)

mainloop()

from tkinter import *
master = Tk()

text=Text(master,width=100,height=100)
text.pack()
photo = PhotoImage(file='leetcode.gif')
def show():
    text.image_create(END,image=photo)

b1 = Button(text,text='点击',command=show)
text.window_create(INSERT,window=b1)

mainloop()

Tags

Tags(标签)通常用于改变Text组件中内容的样式和功能。可以修改文本的字体、尺寸和颜色。另外,Tags还允许将文本、嵌入的组件和图片于键盘和鼠标等事件相关联。除了user-defined tags(用户自定义的Tags),还有一个预定义的特殊Tags:SEL。SEL或者sel用于表示对应的选中内容(如果有的话)。

可以自定义任意数量的Tags,Tags的名字是由普通字符串组成,可以是除了空白字符外的任何字符。另外,任何文本内容都支持多个Tags描述,任何Tags也可以用于描述多个不同的文本内容。为指定文本添加Tags可以使用tag_add()方法

from tkinter import *
master = Tk()

text=Text(master,width=30,height=5)
text.pack()

text.insert(INSERT,'雅俗共赏雅俗共赏雅俗共赏雅俗共赏')
# 行号.列号
text.tag_add('tag1','1.7','1.12','1.14')
text.tag_config('tag1',background='yellow',foreground='red')

mainloop()

使用tag_raise()和tag_lower()来提高和降低某个Tag的优先级。

from tkinter import *
master = Tk()

text=Text(master,width=30,height=5)
text.pack()

# 行号.列号
text.tag_add('tag1','1.7','1.12','1.14')
text.tag_config('tag1',background='yellow',foreground='red')

text.tag_add('tag2','1.7','1.12','1.14')
text.tag_config('tag2',background='blue')
text.tag_lower('tag2')

text.insert(INSERT,'雅俗共赏雅俗共赏雅俗共赏雅俗共赏',('tag2','tag1'))
mainloop()

超链接

from tkinter import *
import webbrowser
root = Tk()

text=Text(root,width=30,height=5)
text.pack()
text.insert(INSERT,'雅俗共赏雅俗共赏雅俗共赏雅俗共赏')

text.tag_add('link','1.7','1.12','1.14')
text.tag_config('link',background='yellow',foreground='red',
                underline=True)
def show_arrow_cursor(event):
    text.config(cursor='arrow')

def show_xterm_cursor(event):
    text.config(cursor='xterm')

def click(event):
    webbrowser.open('http://www.baidu.com')
text.tag_bind('link','<Enter>',show_arrow_cursor)
text.tag_bind('link','<Leave>',show_xterm_cursor)
text.tag_bind('link','<Button-1>',click)

mainloop()

检查功能

from tkinter import *
import hashlib
root = Tk()

text=Text(root,width=30,height=5)
text.pack()
text.insert(INSERT,'雅俗共赏雅俗共赏雅俗共赏雅俗共赏')

contents = text.get('1.0',END)

def getSig(contents):
    m = hashlib.md5(contents.encode())
    return m.digest()

sig = getSig(contents)

def check():
    contents = text.get('1.0',END)
    if sig!=getSig(contents):
        print('内容发生改变')
    else:
        print('内容未发生改变')
Button(root,text='检查',command=check).pack()

mainloop()

mainloop()

全文搜索

from tkinter import *
import hashlib
root = Tk()

text=Text(root,width=30,height=5)
text.pack()
text.insert(INSERT,'雅俗共赏雅俗共赏雅俗共赏雅俗共赏')

def getIndex(text,index):
    return tuple(map(int,str.split(text.index(index),'.')))
start = '1.0'
while True:
    pos = text.search('俗',start,stopindex=END)
    if not pos:
        break
    print(getIndex(text,pos))
    # 指向下一个字符
    start = pos + '+1c'


mainloop()

撤销

from tkinter import *
import hashlib
root = Tk()
"""
# 默认情况下,每一次完整的操作将会放入栈中。但怎么样算是一次完整的操作呢?
# Tkinter 觉得每次焦点切换、用户按下 Enter 键、删除\插入操作的转换等
# 之前的操作算是一次完整的操作,一次的“撤销”操作就会将所有的内容删除。
# 那我们能不能自定义呢?比如我希望插入一个字符就算一次完整的操作,然后
# 点击“撤销”就去掉一个字符。当然可以!
# 做法就是先将autoseparators 选项设置为 False(因为这个选项是让 
# Tkinter 在认为一次完整的操作结束后自动插入“分隔符”),然后绑定键盘事
# 件,每次有输入就用 edit_separator() 方法人为地插入一个“分隔符”。
"""

text=Text(root,width=30,height=5,undo=True,autoseparator=False)
text.pack()
text.insert(INSERT,'雅俗共赏雅俗共赏雅俗共赏雅俗共赏')

def callback(event):
    text.edit_separator()
text.bind('<Key>',callback)

def show():
    text.edit_undo()
Button(root,text='撤销',command=show).pack()

mainloop()

 

 

 

 

 

 

 

 

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZoomToday

给作者倒一杯卡布奇诺

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值