2_Gui_Tkinter(python标准库)

文章目录

  • 官方文档
  • 介绍
  • `Tkinter` 的GUI组件关系
  • 常用组件汇总列表
  • 常见的GUI库
  • 第一个`tkinter` `gui` 程序
  • 经典的GUi程序写法
  • `Label` 标签
  • `Button` 按钮
  • `entry` 单行文本
  • `Text` 多行文本
  • `RadioButton`
  • `Checkbutton`
  • `canvas` 画布
  • `Grid` 布局管理器
  • 计算器软件界面设计
  • `pack` 布局管理器
  • `place` 布局管理器
  • 扑克牌游戏界面设计
  • 事件处理
    • 在这里插入图片描述
  • `lambda` 表达式和属性绑定(`command`方式)
  • 多种事件绑定方法
  • `OptionMenu` 选择项(下拉框)
  • `scale` 滑块使用
  • `colorchooser`颜色选择框
  • `filedialog` 文件对话框
  • `askinteger`简单输入框
  • `messagebox`消息框
  • `Menu`菜单
  • 开发记事本软件的菜单
  • 文件打包分发(`pyinstaller`)
  • 画图软件


官方文档

tkinter -python -中文文档

tkinter官方文档 (英文)

tkinter初学者文档 (英文)

一些例子和接口文档-python - Tkinter (英文)

具体的一些事件列表

一个学习笔记


其他备选 Gui库

更多python - Gui - 库(英文)


介绍

前面写的程序都是控制台,程序和用户的交互通过控制台来完成

现在我们 来学一下 GUI (graphics user interface) ,就是图形界面编程

Gui 编程类似于 搭建积木, 和 Scratch 儿童编程 有点类似。

将一个个 组件(widget)放到窗口中

比如我们使用的 微信 qq 等

既然学习 python 那我们就以 python 自带的编辑器 IDLE 来说明

2_Gui_Tkinter(python标准库)_第1张图片
最上面的 各种按钮 , 比如 file ,edit , shell 等按钮 ,都是一个一个组件。 并且通过 ,增加 对事件 的处理 称为一个完整的程序。(这个编辑器就是 用 tkinter 写的), 其实挺好的唯一 一点就是丑。。。

另外说明一下,整个程序就是一个死循环。 一直监听 你的操作行为, 比如你是否点击了按钮,按下了鼠标等等。


Tkinter 的GUI组件关系

  • object(这是主线)
    • wm
      • tk
      • misc
    • misc
      • Toplevel
      • base widget
        • widget
          • Label
          • Button
          • 等等还有很多
    • pack

  • MiscWm
    • Tkinter 的 Gui 组件的两个根父类
      • Misc : 他是所有组件的根父类
      • Wm : 它 主要提供了 一些与窗口管理器通信的功能函数
        • Tk
          • MiskWm 派生出子类 Tk,它代表应用程序的主窗口。 一般应用程序都需要直接或者间接使用Tk
      • Pack, Place, Grid
        • Pack, Place, Grid 是布局管理器 , 布局管理器 管理组件大小位置 。 通过布局管理器可以将容器中的组件实现合理的排布
        • BaseWidget
          • BaseWidget :是所有组件的父类
        • Widget
          • Widget 是所有组件类的父类,Widget 一共有 四 个父类,BaseWidget , Pack , Grid , Place。 意味着, 所有的 GUI 组件 同时 具备四个 父类属性方法
            2_Gui_Tkinter(python标准库)_第2张图片
            这个类图用 pycharm 可以看。

常用组件汇总列表

Tkinter类 名称 简介
Toplevel 顶层 容器类,可用于其他组件提供的单独的容器:Toplevel 有点类似于窗口
Button 按钮 代表按钮组件
Canvas 画布 提供绘图功能,包括直线,矩形,椭圆,多边形,位图等
Checkbutton 复选框 可供用户勾选的复选框
Entry 单行输入框 用户可输入内容
Frame 容器 用于装载其他Gui 组件
Label 标签 用于显示不可编辑的文本或图标
LabelFrame 容器 也是容器组件,类似于Frame ,但它支持添加标题
ListBox 列表框 列出多个选项,供用户选择
Menu 菜单 菜单组件
Menubutton 菜单按钮 用来包含菜单的按钮,(包括下拉式,层叠式)
OptionMenu 菜单按钮 MenuButton 的子类,也代表菜单按钮,可通过按钮打开一个菜单
Message 消息框 类似于标签,但可以显示多行文本,后来当Label 也能显示多行文本之后, 组件基本处于废弃状态
PanedWindwo 分区窗口 该容器会被划分成多个区域,每添加一个组件占一个区域,用户可通过拖动分隔线来改变各区域的大小
RadioButton 单选按钮 可供用户点击的单选按钮
Scale 滑动条 拖动滑块可设定起始值 和结束值, 可显示当前位置的精确值
Spinbox 微调选择器 用户可通过该组件的向上,向下箭头选择不同的值
Scollbar 滑动条 用于组件(文本域,画布,列表框,文本框)提供滚动功能
Text 多行文本框 显示多行文本

更多的类 可以查看文档

或者使用 tkinter.__dict__ 来查看

In [28]: import tkinter as tk

In [29]: tk.__dict__

# 输出太长就不展示了。
# 下面截个图 。看一部分

属性里都可以看到的。

具体如何看 这篇 基础篇_98节_模块 有详细讲解 如何自学模块。

常见的GUI库

  1. Tkinter
    • tkinter ( Tk interface ) 是Python 的 标准GUI 库, 支持跨平台 的 GUI 程序开发。 适合小型的GUI程序编写。也特别适合初学者学习GUI 编程。所以 原理都是一样的。 学会了 Tkinter 再学其他的 GUI 库 也很简单。
  2. wxPython
    • wxPython 是比较流行的GUI库, 适合大型应用程序开发,功能强于 tkinter . 整体框架类似于 MFC (Microsoft Foundation Classes 微软基础类库)
  3. PyQT
    Qt 是一种开源的Gui 库。 适合 大型 GUI程序开发, PyQt 是Qt 工具包标准的 python 实现 , 我们也可以用Qt 官方 的 Qt Desginer 界面设计快速开发 Gui 程序( 鼠标拖动,设置点参数,非常方便。 )

第一个tkinter gui 程序

# 第一个  tkinter gui程序
from tkinter import *
from tkinter import messagebox
root = Tk()
root.title('我的第一个gui程序')  
# 显示 程序 名称
root.geometry('500x300+100+200')  
# 500 宽度   300是高度   +100  是 距离左边 的位置   +200 是 距离上面的  位置
btn01 = Button(root)
btn01['text'] = 'please click me'

btn01.pack()  # 组件 放到窗口里面


def cool(e):  # e就是 事件对象
    messagebox.showinfo('Message', 'the onepis is a cute boy')
    print('嘻嘻,我好喜欢python')


btn01.bind('', cool)  
# 事件绑定 #  是固定写法。 就是一个事件的名字 button-1 是 左键单击
# 表示 点击这个按钮的时候 就调用 cool 函数。  
# 其实我感觉 这也算是 一种高阶函数的用法。 
# 又很像 回调函数。
 
root.mainloop()  # 调用 组件的mainloop()方法    进入事件循环

2_Gui_Tkinter(python标准库)_第3张图片
2_Gui_Tkinter(python标准库)_第4张图片
print 会在控制台打印信息。


经典的GUi程序写法

from tkinter import *
from tkinter import messagebox


# 测试经典的GUi程序的写法,使用面向对象的方式.
# 继承 Frame
class Application(Frame):
    '''一个经典的GUi程序的写法'''
    def __init__(self, master=None):  # 构造器  构造组件对象
        super().__init__(master)  
        # super()   代表的是 父类的定义,而不是父类对象,调用父类的 构造方法
        # 这里的 master 根据继承的父类是否需要传入参数 来 确认.
        self.master = master
        self.pack()
        self.createWidget()

    def createWidget(self):
        '''创建组件'''
        self.btn01 = Button(self)# 创建一个 按钮
        self.btn01['text'] = 'please click me !' # 设置按钮文本
        self.btn01.pack() # 通过布局管理器显示
        self.btn01['command'] = self.cool # 通过 command 设置 回调函数,或者说 事件响应函数。
        # 绑定事件

        # 创建一个退出按钮
        # 和上面 的 btn01['command'] 性质一样
        # 也可以 btnQuit['command]=root.destroy
        # btnQuit['text']='退出'
        self.btnQuit = Button(
            self,
            text='退出',
            command=root.destroy  # 这里destroy  不要 加  括号 () 因为是 作为参数。 而不是立即调用 执行 destroy 方法
        )  # 写的是退出整个程序 
        # 当然你可以写 self.destroy 这样就退出了 当前 app 
        # 但是还会有一个root 主窗口存在
        self.btnQuit.pack() # 通过布局管理器显示

    def cool(e):
        # e就是 事件对象
        messagebox.showinfo('Message', 'the onepis is a cute boy')
        print('嘻嘻,我好喜欢python')


if __name__ == "__main__":
    root = Tk()  # 创建 根窗口对象
    root.geometry("400x100+200+300")  # 窗口 大小和 位置
    root.title("一个经典的Gui程序类的测试")
    app = Application(master=root)  # 创建 一个虚拟矩形区域 app

    root.mainloop()  # 调用 组件的mainloop()方法 # 进入事件循环

2_Gui_Tkinter(python标准库)_第5张图片


Label 标签

Label - 形参(parameters) 文档

arguments 是实参

约定俗成 的 称呼。

from tkinter import *
from tkinter import messagebox
import os
os.chdir("D:\Python\StudyPython\Jupyter\GUI编程\imgs")
# 关于Label的一些 用法
class Application(Frame):
    '''一个经典的GUi程序的写法'''
    def __init__(self, master=None):  # 构造器  构造组件对象
        super().__init__(master)  
        # super()   代表的是 父类的定义,而不是父类对象,调用父类的 构造方法
        self.master = master
        self.pack()
        self.createWidget()

    def createWidget(self):
        #创建组件
        self.label01 = Label(self,
                             text="python coder or programmer",
                             width=30,
                             height=2,
                             bg="black",
                             fg="white",font=("黑体", 30))
        # text 显示文本
        # width 宽度
        # height 高度
        # bg 背景颜色
        # fg 前景色
        # font 字体的一些属性。比如字号, 字体
        self.label01.pack()  # 布局管理器
        self.label02 = Label(self,
                             text="i love python",
                             width=30,
                             height=2,
                             bg="blue",
                             fg="white",
                             font=("黑体", 30))
        self.label02.pack()  # 布局管理器
        # 显示图像
        global photo
        photo = PhotoImage(file="./a.gif")
        # photo 局部变量 会被销毁,所以需要把 photo 声明 为全局变量  
        # 需要注意,不然无法加载图片  显示图片
        
        # 加载图片
        self.label03 = Label(self, image=photo)  # 设置label
        self.label03.pack()  # 布局管理器
        # 显示多行文本
        self.label04 = Label(self,
                             text="我爱自由,\n在自由面前,\n生命和金钱都可以抛弃!",
                             borderwidth=1, # 边框宽度
                             relief="sunken", # 边框装饰。 实现 虚线等
                             # 可选项 flat无边框 , groove内凹边框, raised凸起, ridge 凸起, solid 实线 ,sunken内凹
                             justify="right") # 多行文本对齐方式
        self.label04.pack()  # 布局管理器

    def cool(e):
        # e就是 事件对象
        messagebox.showinfo('Message', 'the onepis is a cute boy')
        print('嘻嘻,我好喜欢python')

if __name__ == "__main__":
    root = Tk()  # 创建 根窗口对象 
    # 因为在一个程序中只能存在一个根窗口,也就是说只能存在一个Tk()
    # 所以报错的同学
    # 当然一般出现这种情况的都是在命令行下
    # 我们这时候可以输入 root.destroy  退出 root  . 
    # 或者单独运行下 root.mainloop() 然后关掉 弹出的窗口
    root.geometry("800x900+200+300")  # 窗口 大小和 位置
    root.title("测试label标签")

    app = Application(master=root)  # 创建 一个虚拟矩形区域 app

    root.mainloop()  # 调用 组件的mainloop()方法 # 进入事件循环


2_Gui_Tkinter(python标准库)_第6张图片


Button 按钮

#  button 可以是文本 也可以是图像,本质上和 Label 组件使用方法是一样的
from tkinter import *
from tkinter import messagebox


# 测试经典的GUi程序的写法,使用面向对象的方式.
class Application(Frame):
    '''一个经典的GUi程序的写法'''
    def __init__(self, master=None):  # 构造器  构造组件对象
        super().__init__(master)  # super()   代表的是 父类的定义,而不是父类对象,调用父类的 构造方法
        self.master = master
        self.pack()
        self.createWidget()

    def createWidget(self):
        '''创建组件'''
        self.btn01 = Button(self,anchor=E,width=16,height=9) # 设置宽高
        # anchor 可以作为定位用, 东南西北,西北等  NE 是东南西北英文首字母
        self.btn01['text'] = 'please click me' # 设置文本
        self.btn01.pack()
        self.btn01['command'] = self.cool # 绑定事件

        # 创建一个退出按钮
        self.btnQuit = Button(
            self,
            text='退出',
            command=root.destroy  # 这里destroy  不要 加  括号 ()
        )  
        self.btnQuit.pack()

    def cool(e):
        # e就是 事件对象
        messagebox.showinfo('Message', 'the onepis is a cute boy')
        print('嘻嘻,我好喜欢python')


if __name__ == "__main__":
    root = Tk()  # 创建 根窗口对象
    root.geometry("400x600+200+300")  # 窗口 大小和 位置
    root.title("一个经典的Gui程序类的测试")
    app = Application(master=root)  # 创建 一个虚拟矩形区域 app

    root.mainloop()  # 调用 组件的mainloop()方法 # 进入事件循环

2_Gui_Tkinter(python标准库)_第7张图片


"""测试Button组件的基本用法,使用面向对象的方式"""

from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        """创建组件"""
        self.btn01 = Button(root, text="闯荡大海",
                            width=16,height=9,anchor=NE,command=self.login)
        self.btn01.pack()

        global photo
        photo = PhotoImage(file="./start.gif")
        self.btn02 = Button(root, image=photo,command=self.login)
        self.btn02.pack()
        self.btn02.config(state="disabled")  #设置按钮为禁用


    def login(self):
        messagebox.showinfo("海贼王", "成为四王之一!onepis !")


if __name__ == '__main__':
    root = Tk()
    root.geometry("400x130+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第8张图片


entry 单行文本

# entry单行文本框
# 用来接收一行字符串的控件
# 比如输密码的时候 的文本框

"""测试Entry组件的基本用法,使用面向对象的方式"""

from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        """创建登录界面的组件"""
        self.label01 = Label(self,text="用户名")
        self.label01.pack()

        # StringVar变量绑定到指定的组件。
        # StringVar变量的值发生变化,组件内容也变化;
        # 组件内容发生变化,StringVar变量的值也发生变化。
        v1 = StringVar()
        self.entry01 = Entry(self,textvariable=v1)
        self.entry01.pack()
        v1.set("admin")
        print(v1.get());print(self.entry01.get())


        # 创建密码框
        self.label02 = Label(self,text="密码")
        self.label02.pack()

        v2 = StringVar()
        self.entry02 = Entry(self,textvariable=v2, show="*")
        self.entry02.pack()

        Button(self,text="登陆",command=self.login).pack()

    def login(self):
        username = self.entry01.get()
        pwd = self.entry02.get()

        print("去数据库比对用户名和密码!")
        print("用户名:"+username)
        print("密码:"+pwd)

        if username=="onepis" and pwd=="123456":
            messagebox.showinfo("海贼王悬赏系统", "登录成功!去剿灭海军吧!")
        else:
            messagebox.showinfo("海贼王悬赏系统","登录失败!你是海军的奸细吧!")


if __name__ == '__main__':
    root = Tk()
    root.geometry("400x130+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第9张图片
2_Gui_Tkinter(python标准库)_第10张图片


Text 多行文本

"""测试Text多行文本框组件的基本用法,使用面向对象的方式"""

from tkinter import *
import webbrowser

class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        self.w1 = Text(root, width=40, height=12,bg="white")
        # 宽度20个字母(10个汉字),高度一个行高
        self.w1.pack()

        self.w1.insert(1.0, "0123456789\nabcdefg")# 第一行第0列
        self.w1.insert(2.3, "锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦\n") # 第2行第3列 插入文本



        Button(self,text="重复插入文本",command=self.insertText).pack(side="left")
        # side 默认是垂直排列  ,left 左对齐
        Button(self,text="返回文本",command=self.returnText).pack(side="left")
        Button(self,text="添加图片",command=self.addImage).pack(side="left")
        Button(self,text="添加组件",command=self.addWidget).pack(side="left")
        Button(self,text="通过tag精确控制文本",command=self.testTag).pack(side="left")

    def insertText(self):
        # INSERT索引表示在光标处插入
        self.w1.insert(INSERT, ' pis1 ')
        # END索引号表示在最后插入
        self.w1.insert(END, '[programming]')
        self.w1.insert(1.8, "onepis")# 第一行 8列插入文本


    def returnText(self):
        # Indexes(索引)是用来指向Text组件中文本的位置,Text的组件索引也是对应实际字符之间的位置。
        # 核心:行号以1开始 列号以0开始
        print(self.w1.get(1.2, 1.6))# 返回2345
        print("所有文本内容:\n"+self.w1.get(1.0, END))

    def addImage(self):
        # global photo  # 或者 可以定义为下面的 对象的一个属性
        self.photo = PhotoImage(file="./a.gif")
        self.w1.image_create(END, image=self.photo)

    def addWidget(self):
        b1 = Button(self.w1, text='爱编程')
        # 在text创建组件的命令
        self.w1.window_create(INSERT, window=b1)

    def testTag(self):
        self.w1.delete(1.0,END)
        self.w1.insert(INSERT, "good good study,day day up!\n我爱写代码\n程序员\n百度,搜一下就知道")
        self.w1.tag_add("good", 1.0, 1.9) # 添加标记 1行0 列。 到 1行9列
        self.w1.tag_config("good", background="yellow", foreground="red")# 标记 颜色 背景色设为黄色 前景色 设为红色

        self.w1.tag_add("baidu", 4.0, 4.2)
        self.w1.tag_config("baidu", underline=True)
        self.w1.tag_bind("baidu", "", self.webshow)# 绑定事件 可以

    def webshow(self,event):
        webbrowser.open("http://www.baidu.com")

if __name__ == '__main__':
    root = Tk()
    root.geometry("450x300+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第11张图片


RadioButton

"""测试Radiobutton组件的基本用法,使用面向对象的方式"""

from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        self.v = StringVar();
        self.v.set("F")# 默认是把女性选中了

        self.r1 = Radiobutton(self, text="男性", value="M", variable=self.v)# man
        self.r2 = Radiobutton(self, text="女性", value="F", variable=self.v)# 

        self.r1.pack(side="left");self.r2.pack(side="left")# 通过分号把两个语句隔开

        Button(self, text="确定", command=self.confirm).pack(side="left")

    def confirm(self):
        messagebox.showinfo("测试","选择的性别:"+self.v.get())

if __name__ == '__main__':
    root = Tk()
    root.geometry("400x50+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第12张图片


Checkbutton

"""测试Checkbutton组件的基本用法,使用面向对象的方式"""
# 复选按钮 用法和单选框,单选按钮是一样的
from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        self.codeHobby = IntVar();
        self.videoHobby = IntVar()

        print(self.codeHobby.get())  # 默认值是0
        self.c1 = Checkbutton(self, text="敲代码",
                              variable=self.codeHobby, onvalue=1, offvalue=0)
        self.c2 = Checkbutton(self, text="看视频",
                              variable=self.videoHobby, onvalue=1, offvalue=0)

        self.c1.pack(side="left");self.c2.pack(side="left")

        Button(self, text="确定", command=self.confirm).pack(side="left")


    def confirm(self):
        if self.videoHobby.get() == 1:
            messagebox.showinfo("测试","看视频,都是正常人有的爱好!你喜欢看什么类型?")
        if self.codeHobby.get() == 1:
            messagebox.showinfo("测试","抓获野生程序猿一只,赶紧送给他学习视频充饥吧!")



if __name__ == '__main__':
    root = Tk()
    root.geometry("400x50+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第13张图片


canvas 画布

# canvas画布
#基本用法
"""测试Canvas组件的基本用法,使用面向对象的方式"""

from tkinter import *
from tkinter import messagebox
import random



class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        self.canvas = Canvas(self, width=300, height=200, bg="green")
        self.canvas.pack()
        # 画一条直线
        line = self.canvas.create_line(10, 10, 30, 20, 40, 50)
        # 10 10 是一个点的坐标, 30,20 又是 一个坐标,甚至元组或者 列表放进去 也可以的
        # 画一个矩形.
        rect = self.canvas.create_rectangle(50, 50, 100, 100)# 50,50 指的是左上角的坐标,到右下角的坐标100,100
        # 画一个椭圆.坐标两双。为椭圆的边界矩形左上角和底部右下角
        oval = self.canvas.create_oval(50, 50, 100, 100)# 指的是外切矩形的 坐标

        global photo
        photo = PhotoImage(file="./a.gif")
        self.canvas.create_image(150,170,image=photo)

        Button(self, text="画10个矩形", command=self.draw50Recg).pack(side="left")

    def draw50Recg(self):
        for i in range(0, 10):
            x1 = random.randrange(int(self.canvas["width"])/2)
            y1 = random.randrange(int(self.canvas["height"])/2)
            x2 = x1 + random.randrange(int(self.canvas["width"])/2)
            y2 = y1 + random.randrange(int(self.canvas["height"])/2)
            self.canvas.create_rectangle(x1, y1, x2, y2)


if __name__ == '__main__':
    root = Tk()
    root.geometry("400x300+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第14张图片


Grid 布局管理器

"""测试Grid布局管理器的基本用法,使用面向对象的方式"""
# tkinter 提供3种 布局管理器
# pack grid place
# grid是表格布局  比较常用和典型  
from tkinter import *
from tkinter import messagebox
import random



class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        """通过grid布局实现登录界面"""
        self.label01 = Label(self,text="用户名")
        self.label01.grid(row=0,column=0)# 通过行列定位0行 0列
        self.entry01 = Entry(self)
        self.entry01.grid(row=0,column=1)
        Label(self,text="用户名为手机号").grid(row=0,column=2)

        Label(self, text="密码").grid(row=1, column=0)
        Entry(self, show="*").grid(row=1, column=1)

        Button(self, text="登录").grid(row=2, column=1, sticky=EW)# 也是东南西北中 以及4个脚,也可以ws,西东 拉伸
        Button(self, text="取消").grid(row=2, column=2, sticky=E)



if __name__ == '__main__':
    root = Tk()
    root.geometry("400x90+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第15张图片


计算器软件界面设计


"""计算器软件界面的设计"""
# 小实例
# 做一个计算器的界面
from tkinter import *
from tkinter import messagebox
import random



class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        """通过grid布局实现计算器的界面"""
        btnText = (("MC","M+","M-","MR"),
                   ("C","±","/","*"),
                   (7,8,9,"-"),
                   (4,5,6,"+"),
                   (1,2,3,"="),
                   (0,"."))
        # 输入文本框
        Entry(self).grid(row=0,column=0,columnspan=4,pady=10)
        # 输入按钮
        for rindex,r in enumerate(btnText):
            for cindex,c in enumerate(r):
                if c == "=":
                    Button(self,text=c,width=2).grid(row=rindex+1,column=cindex,sticky=NSEW,rowspan=2)# 设置按钮,sticky 东南西北都贴住  
                    # 设置跨行 rowspan
                elif c == 0 :
                    Button(self,text=c,width=2).grid(row=rindex+1,column=cindex,sticky=NSEW,columnspan=2)# 设置按钮,sticky 东南西北都贴住
                elif c == "." :
                    Button(self,text=c,width=2).grid(row=rindex+1,column=cindex+1,sticky=NSEW)# 设置按钮,sticky 东南西北都贴住
                else:
                    Button(self,text=c,width=2).grid(row=rindex+1,column=cindex,sticky=NSEW)# 设置按钮,sticky 东南西北都贴住


if __name__ == '__main__':
    root = Tk()
    root.geometry("200x250+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第16张图片


pack 布局管理器

#pack布局管理器
# coding=utf-8
# 测试pack布局管理
#如上列出了 pack 布局所有的属性, 但是不需
# 要挨个熟悉, 了解基本的即可。 pack 适用于简单的垂直或水
# 平排布, 如果需要复杂的布局可以使用 grid 或 place。
from tkinter import *

root = Tk();root.geometry("700x220")

# Frame是一个矩形区域,就是用来放置其他子组件
f1 = Frame(root)
f1.pack()
f2 = Frame(root)
f2.pack()

btnText = ("流行风","中国风","日本风","重金属","轻音乐")

for txt in btnText:
    Button(f1,text=txt).pack(side="left",padx="10")
# side =left 水平排布
for i in range(1,13):
    Label(f2,width=5,height=10,borderwidth=1,relief="solid",
          bg="black" if i%2==0 else "white").pack(side="left",padx=2)
            # 这样的 if  else 更方便一些
root.mainloop()

2_Gui_Tkinter(python标准库)_第17张图片


place 布局管理器

# place 布局管理器
# place 布局管理器可以通过坐标精确控制组件的位置, 适用
# 于一些布局更加灵活的场景。
# coding=utf-8
from tkinter import *

root = Tk();root.geometry("500x300")#  500宽 300 高
root.title("布局管理place");root["bg"]="white"

f1 = Frame(root,width=200,height=200,bg="green")
f1.place(x=30,y=30)
# 宽度用的是相对高度 相对于root父容器 主要是 定位的用法
Button(root,text="python").place(relx=0.2,x=100,y=20,relwidth=0.2,relheight=0.5)
Button(f1,text="程序员").place(relx=0.6,rely=0.7)
Button(f1,text="Crawl").place(relx=0.5,rely=0.2)
root.mainloop()

2_Gui_Tkinter(python标准库)_第18张图片


扑克牌游戏界面设计

"""扑克牌游戏的界面设计"""
# 通过 place 布局管理器做一个扑克牌 游戏界面,并且增加一个出牌 事件
from tkinter import *


class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.pack()
        self.createWidget()


    def createWidget(self):
        """通过place布局管理器实现扑克牌位置控制"""
        # self.photo = PhotoImage(file="./puke/puke1.gif")
        # self.puke1 = Label(self.master,image=self.photo)
        # self.puke1.place(x=10,y=50)

        self.photos=[PhotoImage(file="./puke/puke"+str(i+1)+".gif") for i in range(10) ]
        self.pukes=[Label(self.master,image=self.photos[i]) for i in range(10) ]
        for i in range(10):
            self.pukes[i].place(x=10+40*i,y=50)# 放入布局管理器中 显示

        self.pukes[0].bind_class("Label","",self.chupai)


    def chupai(self,event):# event  事件
        print(event.widget.winfo_geometry())
        print(event.widget.winfo_y())
        if  event.widget.winfo_y()==50:
            event.widget.place(y=30)
        else:
            event.widget.place(y=50)
if __name__ == '__main__':
    root = Tk()
    root.geometry("600x270+200+300")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第19张图片
2_Gui_Tkinter(python标准库)_第20张图片


事件处理

# 事件处理
# 一个 GUI 应用整个生命周期都处在一个消息循环 (event
# loop) 中。 它等待事件的发生, 并作出相应的处理。
# Tkinter 提供了用以处理相关事件的机制. 处理函数可被绑
# 定给各个控件的各种事件。
# widget.bind(event, handler)
#    鼠标左键按下 2 表示中键, 3 表示右键
#   
# <1>  也可以执行, 就是鼠标单击的意思

# coding=utf-8
# 测试键盘和鼠标事件

from tkinter import *

root = Tk();root.geometry("530x300")

c1 = Canvas(root,width=200,height=200,bg="green")
c1.pack()


def mouseTest(event):
    print("鼠标左键单击位置(相对于父容器):{0},{1}".format(event.x,event.y))
    # 左键单击打印坐标
    print("鼠标左键单击位置(相对于屏幕):{0},{1}".format(event.x_root,event.y_root))
    # 左键单击打印坐标
    print("事件绑定的组件:{0}".format(event.widget))
    # 打印绑定的组件
def testDrag(event):
    c1.create_oval(event.x,event.y,event.x+1,event.y+1)
    #  画圆

def keyboardTest(event):
    print("键的keycode:{0},键的char:{1},键的keysym:{2}"
          .format(event.keycode,event.char,event.keysym))

def press_a_test(event):
    print("press a")

def release_a_test(event):
    print("release a")


c1.bind("",mouseTest)#  左键点击的方法 绑定的是
c1.bind("",testDrag)#  拖动 的时候做什么  testdrag


root.bind("",keyboardTest)# 对任意键  都响应
root.bind("",press_a_test)          #只针对小写的a,大写的A不管用
root.bind("",release_a_test)# 对释放a键做相应

root.mainloop()

在绿色区域监听鼠标键盘的操作

2_Gui_Tkinter(python标准库)_第21张图片

lambda 表达式和属性绑定(command方式)

# lambda表达式 详解
# lambda 定义的匿名函数也有输入、 也有输出, 只是没有名
# 字。 语法格式如下:
# lambda 参数值列表: 表达式
# 参数值列表即为输入。
# 表达式计算的结构即为输出。
# 传入 参数
# coding=utf-8
# 测试command属性绑定事件,测试lambda表达式帮助传参
# 使用 lambda 帮助 command 属性绑定时传参
from tkinter import *

root = Tk();root.geometry("270x50")


def mouseTest1():
    print("command方式,简单情况:不涉及获取event对象,可以使用")


def mouseTest2(a,b):
    print("a={0},b={1}".format(a,b))


Button(root, text="测试command1",
       command=mouseTest1).pack(side="left")
# 这种方式适合 不获取 event 对象的方式
Button(root, text="测试command2",
       command=lambda: mouseTest2("onepis", "hasaki")).pack(side="left")
# lambda 方式 传入方法   函数  传递参数
root.mainloop()

2_Gui_Tkinter(python标准库)_第22张图片


多种事件绑定方法

# 多种事件 绑定方式汇总
# coding=utf-8
# 多种事件绑定方式汇总

# 组件对象的绑定
# 1. 通过 command 属性绑定(适合简单不需获取 event 对象)
# Button(root,text=”登录”,command=login)
# 2. 通过 bind()方法绑定(适合需要获取 event 对象)
# c1 = Canvas(); c1.bind(“”,drawLine)

# · 组件类的绑定
# 调用对象的 bind_class 函数, 将该组件类所有的组件绑定事件:
# w.bind_class(“Widget”,”event”,eventhanler)
# 比如: btn01.bind_class(“Button”,””,func)
from tkinter import *

root = Tk();root.geometry("270x30")


def mouseTest1(event):
    print("bind()方式绑定,可以获取event对象")
    print(event.widget)


def mouseTest2(a, b):
    print("a={0},b={1}".format(a, b))
    print("command方式绑定,不能直接获取event对象")


def mouseTest3(event):
    print("右键单击事件,绑定给所有按钮啦!!")
    print(event.widget)


b1 = Button(root, text="测试bind()绑定")
b1.pack(side="left")
# bind方式绑定事件 2 是滚轮按钮
b1.bind("", mouseTest1)

# command属性直接绑定事件
b2 = Button(root, text="测试command2",
       command=lambda: mouseTest2("onepis", "hasaki"))
b2.pack(side="left")


# 给所有Button按钮都绑定右键单击事件
b1.bind_class("Button","", mouseTest3)

root.mainloop()

2_Gui_Tkinter(python标准库)_第23张图片

OptionMenu 选择项(下拉框)

# OptionMenu 选择项
# OptionMenu(选择项)用来做多选一, 选中的项会在顶部显
# 示。

"""optionmenu的使用测试"""


from tkinter import *

root = Tk(); root.geometry("200x100")
v = StringVar(root)
v.set("the Yamateh")
om = OptionMenu(root, v, "onepis", "hasaki", "yaphets")

om["width"] = 10
om.pack()


def test1():
    print("perfect is shit :", v.get())
#    v.set("尚学堂")       # 直接修改了optionmenu中选中的值


Button(root, text="确定", command=test1).pack()

root.mainloop()

2_Gui_Tkinter(python标准库)_第24张图片
2_Gui_Tkinter(python标准库)_第25张图片


scale 滑块使用

"""scale滑块的使用测试"""
# Scale 移动滑块
# Scale(移动滑块)用于在指定的数值区间, 通过滑块的移动来
# 选择值
from tkinter import *

root = Tk();root.geometry("400x150")


def test1(value):
    print("滑块的值:",value)
    newFont = ("宋体",value)
    a.config(font=newFont)
    # 设置字体 字体为宋体  字号 为滑块的值

s1 = Scale(root,from_=10,to=50,length=200,tickinterval=5,orient=HORIZONTAL,command=test1)
# length 长度 ,宽度的意思  orient=HORIZONTAL   默认是垂直的 ,现在是  水平的 
# from_=10  开始   to   结束   tickinterval=5  相当于步长   command 调用方法 test1 也就是事件
s1.pack()

a = Label(root,text="onepeace",width=10,height=1,bg="black",fg="white")
a.pack()


root.mainloop()

2_Gui_Tkinter(python标准库)_第26张图片


colorchooser颜色选择框

# 颜色选择框

"""askcolor颜色选择框的测试,改变背景色"""

from tkinter import  *
from tkinter.colorchooser import *

root = Tk();root.geometry("400x150")


def test1():
    s1 = askcolor(color="red", title="选择背景色")
    print(s1)
    # 前三位是 rgb 颜色 表示法
    # 第二个是  16进制码 表示
    # s1的值是:((0.0, 0.0, 255.99609375), '#0000ff')
    root.config(background=s1[1])
    # 设置颜色

Button(root,text="选择背景色",command=test1).pack()

root.mainloop()

2_Gui_Tkinter(python标准库)_第27张图片


filedialog 文件对话框

 """文件对话框获取文件"""
# 文件对话框帮助我们实现可视化的操作目录、 操作文件。 最
# 后, 将文件、 目录的信息传入到程序中。 
from tkinter import  *
from tkinter.filedialog import *

root = Tk();root.geometry("400x100")


def test1():
    f = askopenfilename(title="上传文件",
                        initialdir="f:",filetypes=[("视频文件",".mp4")])
                        # 实现文件的过滤filetypes
                        # initialdir="f:"  初始化的打开目录  
    # print(f)
    show["text"]=f


Button(root,text="选择编辑的视频文件",command=test1).pack()

show = Label(root,width=40,height=3,bg="green")
show.pack()

root.mainloop()

2_Gui_Tkinter(python标准库)_第28张图片






#coding=utf-8
"""文件对话框获取文件"""
# 文件对话框帮助我们实现可视化的操作目录、 操作文件。 最
# 后, 将文件、 目录的信息传入到程序中。 

from tkinter import  *
from tkinter.filedialog import *

root = Tk();root.geometry("400x500")

def test1():
	# -filetypes, -initialdir, -initialfile, -multiple, -parent, -title, or -typevariable
    # with askopenfile(title="上传文件",
    #                  initialdir="d:",filetypes=[("文本文件",".txt")]) as f:
    # 如果上面的代码 读取 文档 报编码错误。那么 可以使用下面这个函数
    with open(askopenfilename(), encoding='utf-8') as f:
        show["text"]=f.read()
        # 读取文件


Button(root,text="选择读取的文本文件",command=test1).pack()

show = Label(root,width=400,height=300,bg="gray") 
show.pack()

root.mainloop()

2_Gui_Tkinter(python标准库)_第29张图片

askinteger简单输入框

"""简单输入对话框"""
from tkinter.simpledialog import *

root = Tk();root.geometry("400x100")


def test1():
    a = askinteger(title="输入年龄",prompt="请输入年龄",initialvalue=18,minvalue=1,maxvalue=150)
   # askstring、askfloat框使用方式一样
   # 简单对话框.prompt   提问      
   # initialvalue=18  默认值  
    show["text"]=a


Button(root,text="hey,how old are you?",command=test1).pack()

show = Label(root,width=40,height=3,bg="green")
show.pack()

root.mainloop()

2_Gui_Tkinter(python标准库)_第30张图片
2_Gui_Tkinter(python标准库)_第31张图片


messagebox消息框

# 消息框
# 如果遇到较复杂的 界面 
# 推荐使用 wxpython
# 和 PyQt 模块 
"""通用消息框"""

from tkinter import  *
from tkinter.messagebox import *

root = Tk();root.geometry("400x100")

a1 = showinfo(title="程序员",message="the perfect is shit\n大多数人都生活在平静的绝望之中,行将就木之际,还未唱出心底的生命之歌!\n在这个世界上,取得成功的人是那些努力寻找他们想要的机会的人,如果找不到机会,那就创造机会!\n所谓勇敢并不意味着,无所畏惧,无所畏惧其实是一种心理疾病!\n要胆大妄为,要标新立异,要不切实际,要追求一切能够将意义和富于想象力的美好前景结合起来的东西,并以此挑战那些不敢越雷池半步的人,平庸的物种,及平凡普通的奴隶!")
print(a1)

root.mainloop()

2_Gui_Tkinter(python标准库)_第32张图片

Menu菜单

# 菜单
#coding=utf-8

#记事本软件,练习主菜单的设计

from tkinter.filedialog import *

root = Tk();root.geometry("400x400")

#创建主菜单栏
menubar = Menu(root)

#创建子菜单
menuFile = Menu(menubar)
menuEdit = Menu(menubar)
menuHelp = Menu(menubar)

#将子菜单加入到主菜单栏
menubar.add_cascade(label="文件(F)",menu=menuFile)
menubar.add_cascade(label="编辑(E)",menu=menuEdit)
menubar.add_cascade(label="帮助(H)",menu=menuHelp)

filename = ""


def openfile():
    global filename
    w1.delete('1.0', 'end')         # 先把Text控件中的内容清空 
    # with askopenfile(title="打开文件") as f: # 如果编码错误,请使用 askopenfilename
    #     content = f.read()
    #     w1.insert(INSERT, content)
    #     filename = f.name
    #     print(f.name)
    with open(askopenfilename(), encoding='utf-8') as f:
        content = f.read()
        w1.insert(INSERT, content)
        filename = f.name
        print(f.name)
	

def savefile():
    with open(filename, "w") as f:
        content = w1.get(1.0, END)
        f.write(content)


def exit():
    root.quit()



# 添加菜单项
menuFile.add_command(label="打开", accelerator="ctrl+o", command=openfile)
menuFile.add_command(label="保存", command=savefile)
menuFile.add_separator()  # 添加分割线
menuFile.add_command(label="退出", command=exit)

# 将主菜单栏加到根窗口
root["menu"] = menubar

w1 = Text(root, width=50, height=30)
w1.pack()


root.mainloop()

2_Gui_Tkinter(python标准库)_第33张图片
2_Gui_Tkinter(python标准库)_第34张图片


开发记事本软件的菜单

"""开发记事本软件的菜单"""

from tkinter.filedialog import *
from tkinter.colorchooser import *

class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.textpad = None             # textpad表示Text文本框对象
        self.pack()
        self.createWidget()

    def createWidget(self):
        # 创建主菜单栏
        menubar = Menu(root)

        # 创建子菜单
        menuFile = Menu(menubar)
        menuEdit = Menu(menubar)
        menuHelp = Menu(menubar)

        # 将子菜单加入到主菜单栏
        menubar.add_cascade(label="文件(F)", menu=menuFile)
        menubar.add_cascade(label="编辑(E)", menu=menuEdit)
        menubar.add_cascade(label="帮助(H)", menu=menuHelp)

        # 添加菜单项
        menuFile.add_command(label="新建", accelerator="ctrl+n", command=self.test)
        menuFile.add_command(label="打开", accelerator="ctrl+o", command=self.test)
        menuFile.add_command(label="保存", accelerator="ctrl+s",command=self.test)
        menuFile.add_separator()  # 添加分割线
        menuFile.add_command(label="退出", accelerator="ctrl+q",command=self.test)

        # 将主菜单栏加到根窗口
        root["menu"] = menubar


        #文本编辑区
        self.textpad = Text(root, width=50, height=30)
        self.textpad.pack()

        # 创建上下菜单
        self.contextMenu = Menu(root)
        self.contextMenu.add_command(label="背景颜色", command=self.test)

        #为右键绑定事件
        root.bind("",self.createContextMenu)

    def test(self):
        pass

    def createContextMenu(self,event):
        # 菜单在鼠标右键单击的坐标处显示
        self.contextMenu.post(event.x_root, event.y_root)


if __name__ == '__main__':
    root = Tk()
    root.geometry("450x300+200+300")
    root.title("程序员的简易记事本")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第35张图片


# 相对比较完整的记事本软件开发

from tkinter.filedialog import *
from tkinter.colorchooser import *


class Application(Frame):

    def __init__(self, master=None):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.textpad = None             # textpad表示Text文本框对象
        self.pack()
        self.createWidget()

    def createWidget(self):
        # 创建主菜单栏
        menubar = Menu(root)

        # 创建子菜单
        menuFile = Menu(menubar)
        menuEdit = Menu(menubar)
        menuHelp = Menu(menubar)

        # 将子菜单加入到主菜单栏
        menubar.add_cascade(label="文件(F)", menu=menuFile)
        menubar.add_cascade(label="编辑(E)", menu=menuEdit)
        menubar.add_cascade(label="帮助(H)", menu=menuHelp)

        # 添加菜单项
        menuFile.add_command(label="新建", accelerator="ctrl+n", command=self.newfile)
        menuFile.add_command(label="打开", accelerator="ctrl+o", command=self.openfile)
        menuFile.add_command(label="保存", accelerator="ctrl+s",command=self.savefile)
        menuFile.add_separator()  # 添加分割线
        menuFile.add_command(label="退出", accelerator="ctrl+q",command=self.exit)

        # 将主菜单栏加到根窗口
        root["menu"] = menubar

        # 增加快捷键的处理
        root.bind("",lambda event:self.newfile())
        root.bind("",lambda event:self.openfile())
        root.bind("",lambda event:self.savefile())
        root.bind("",lambda event:self.exit())

        #文本编辑区
        self.textpad = Text(root, width=50, height=30)
        self.textpad.pack()

        # 创建上下菜单
        self.contextMenu = Menu(root)
        self.contextMenu.add_command(label="背景颜色", command=self.openAskColor)

        #为右键绑定事件
        root.bind("",self.createContextMenu)

    def newfile(self):
        self.textpad.delete("1.0", "end")  # 把text控件中所有的内容清空
        self.filename= asksaveasfilename(title="另存为",initialfile="未命名.txt",
                          filetypes=[("文本文档","*.txt")],
                          defaultextension=".txt")
        self.savefile()

    def openfile(self):
        self.textpad.delete("1.0","end")        # 把text控件中所有的内容清空
        with askopenfile(title="打开文本文件") as f:
            self.textpad.insert(INSERT,f.read())
            self.filename = f.name

    def savefile(self):
        with open(self.filename,"w") as f:
            c = self.textpad.get(1.0,END)
            f.write(c)

    def exit(self):
        root.quit()

    def openAskColor(self):
        s1 = askcolor(color="red",title="选择背景色")
        self.textpad.config(bg=s1[1])
    def createContextMenu(self,event):
        # 菜单在鼠标右键单击的坐标处显示
        self.contextMenu.post(event.x_root, event.y_root)


if __name__ == '__main__':
    root = Tk()
    root.geometry("450x300+200+300")
    root.title("程序员的简易记事本")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第36张图片


文件打包分发(pyinstaller

pyinstaller 文档(英文))

# pyinstaller打包文件
# pyinstaller -F xxxx.py
# 【注】 相关参数如下:
# --icon=图标路径(pyinstaller -F --icon=my.ico XXXX.py)
# -F 打包成一个 exe 文件
# -w 使用窗口, 无控制台
# -c 使用控制台, 无窗口
# -D 创建一个目录, 里面包含 exe 以及其他一些依赖性文件

画图软件

# 开发一款简单的画图软件, 包含如下功能:
# 1. 画笔
# 2. 矩形/椭圆绘制
# 3. 清屏
# 4. 橡皮擦
# 5. 直线/带箭头的直线
# 6. 修改画笔颜色、 背景颜色
"""开发画图软件的菜单
"""

from tkinter.filedialog import *
from tkinter.colorchooser import *

#窗口的宽度和高度
win_width=900
win_height=450


class Application(Frame):

    def __init__(self, master=None,bgcolor="#000000"):
        super().__init__(master)        # super()代表的是父类的定义,而不是父类对象
        self.master = master
        self.bgcolor=bgcolor
        self.x = 0
        self.y = 0
        self.fgcolor = "#ff0000"
        self.lastDraw = 0               # 表示最后绘制的图形的id
        self.startDrawFlag = False
        self.pack()
        self.createWidget()

    def createWidget(self):
        # 创建绘图区
        self.drawpad = Canvas(root,width=win_width,height=win_height*0.9,bg=self.bgcolor)
        self.drawpad.pack()

        #创建按钮
        btn_start = Button(root,text="开始",name="start")
        btn_start.pack(side="left",padx="10")
        btn_pen = Button(root,text="画笔",name="pen")
        btn_pen.pack(side="left",padx="10")
        btn_rect = Button(root,text="矩形",name="rect")
        btn_rect.pack(side="left",padx="10")
        btn_clear = Button(root,text="清屏",name="clear")
        btn_clear.pack(side="left",padx="10")
        btn_erasor = Button(root,text="橡皮擦",name="erasor")
        btn_erasor.pack(side="left",padx="10")
        btn_line = Button(root,text="直线",name="line")
        btn_line.pack(side="left",padx="10")
        btn_lineArrow = Button(root,text="箭头直线",name="lineArrow")
        btn_lineArrow.pack(side="left",padx="10")
        btn_color = Button(root,text="颜色",name="color")
        btn_color.pack(side="left",padx="10")

        #事件处理
        btn_pen.bind_class("Button","<1>",self.eventManager)
        self.drawpad.bind("",self.stopDraw)

        #增加颜色切换的快捷键
        root.bind("",self.kuaijiejian)
        root.bind("",self.kuaijiejian)
        root.bind("",self.kuaijiejian)

    def eventManager(self,event):
        name = event.widget.winfo_name()
        print(name)
        if name=="line":
            self.drawpad.bind("",self.myline)
        elif name=="lineArrow":
            self.drawpad.bind("",self.mylineArrow)
        elif name=="rect":
            self.drawpad.bind("",self.myRect)
        elif name=="pen":
            self.drawpad.bind("",self.myPen)
        elif name=="erasor":
            self.drawpad.bind("",self.myErasor)
        elif name=="clear":
            self.drawpad.delete("all")
        elif name=="color":
            c = askcolor(color=self.fgcolor,title="选择画笔颜色")
            #[(255,0,0),"#ff0000"]
            self.fgcolor = c[1]
            # 修改颜色
    def stopDraw(self,event):
        self.startDrawFlag = False
        self.lastDraw = 0
        # 赋值 为 0  发生事件的时候,然后再myline  开始画的时候就删除不到 了
    def startDraw(self,event):
        self.drawpad.delete(self.lastDraw)

        if not self.startDrawFlag:
            self.startDrawFlag = True
            self.x = event.x
            self.y = event.y

    def myline(self,event):
        self.startDraw(event)
        self.lastDraw = self.drawpad.create_line(self.x,self.y,event.x,event.y,fill=self.fgcolor)

    def mylineArrow(self,event):
        self.startDraw(event)
        self.lastDraw = self.drawpad.create_line(self.x,self.y,event.x,event.y,arrow=LAST,fill=self.fgcolor)
        
    def myRect(self,event):
        self.startDraw(event)
        self.lastDraw = self.drawpad.create_rectangle(self.x,self.y,event.x,event.y,outline=self.fgcolor)

    def myPen(self,event):
        self.startDraw(event)
        self.drawpad.create_line(self.x,self.y,event.x,event.y,fill=self.fgcolor)
        #这里不指定给 lastdraw  就可以实现多次  画笔  画线
        self.x = event.x
        self.y = event.y

    def myErasor(self,event):
        self.startDraw(event)
        self.drawpad.create_rectangle(event.x-4,event.y-4,event.x+4,event.y+4,fill=self.bgcolor)
        self.x = event.x
        self.y = event.y# 可删除 直接大矩形     套接  删除颜色

    def kuaijiejian(self,event):
        if event.char =="r":
            self.fgcolor = "#ff0000"
        elif event.char =="g":
            self.fgcolor = "#00ff00"
        elif event.char =="y":
            self.fgcolor = "#ffff00"

if __name__ == '__main__':
    root = Tk()
    root.geometry(str(win_width)+"x"+str(win_height)+"+200+300")
    root.title("onepis的画图软件")
    app = Application(master=root)
    root.mainloop()

2_Gui_Tkinter(python标准库)_第37张图片

你可能感兴趣的:(自学Python笔记(进阶篇),python,gui,tkinter)