2_Gui_Tkinter(python标准库)


官方文档

tkinter -python -中文文档

tkinter官方文档 (英文)

tkinter初学者文档 (英文)

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

具体的一些事件列表

一个学习笔记


其他备选 Gui库

更多python - Gui - 库(英文)


介绍

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

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

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

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

比如我们使用的 微信 qq 等

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

在这里插入图片描述
最上面的 各种按钮 , 比如 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 组件 同时 具备四个 父类属性方法
            在这里插入图片描述
            这个类图用 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('<Button-1>', cool)  
# 事件绑定 # <Button-1> 是固定写法。 就是一个事件的名字 button-1 是 左键单击
# 表示 点击这个按钮的时候 就调用 cool 函数。  
# 其实我感觉 这也算是 一种高阶函数的用法。 
# 又很像 回调函数。
 
root.mainloop()  # 调用 组件的mainloop()方法    进入事件循环

在这里插入图片描述
在这里插入图片描述
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()方法 # 进入事件循环

在这里插入图片描述


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()方法 # 进入事件循环


在这里插入图片描述


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()方法 # 进入事件循环

在这里插入图片描述


"""测试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()

在这里插入图片描述


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()

在这里插入图片描述
在这里插入图片描述


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", "<Button-1>", 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()

在这里插入图片描述


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()

在这里插入图片描述


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()

在这里插入图片描述


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()

在这里插入图片描述


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()

在这里插入图片描述


计算器软件界面设计


"""计算器软件界面的设计"""
# 小实例
# 做一个计算器的界面
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()

在这里插入图片描述


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()

在这里插入图片描述


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()

在这里插入图片描述


扑克牌游戏界面设计

"""扑克牌游戏的界面设计"""
# 通过 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","<Button-1>",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()

在这里插入图片描述
在这里插入图片描述


事件处理

# 事件处理
# 一个 GUI 应用整个生命周期都处在一个消息循环 (event
# loop) 中。 它等待事件的发生, 并作出相应的处理。
# Tkinter 提供了用以处理相关事件的机制. 处理函数可被绑
# 定给各个控件的各种事件。
# widget.bind(event, handler)
# <Button-1>   鼠标左键按下 2 表示中键, 3 表示右键
# <ButtonPress-1>  <ButtonRelease-1>
# <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("<Button-1>",mouseTest)#  左键点击的方法 绑定的是
c1.bind("<B1-Motion>",testDrag)#  拖动 的时候做什么  testdrag


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

root.mainloop()

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

在这里插入图片描述

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()


多种事件绑定方法

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

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

# · 组件类的绑定
# 调用对象的 bind_class 函数, 将该组件类所有的组件绑定事件:
# w.bind_class(“Widget”,”event”,eventhanler)
# 比如: btn01.bind_class(“Button”,”<Button-1>”,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("<Button-2>", mouseTest1)

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


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

root.mainloop()

在这里插入图片描述

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()

在这里插入图片描述
在这里插入图片描述


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()

在这里插入图片描述


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()

在这里插入图片描述


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()

在这里插入图片描述






#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()

在这里插入图片描述

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()

在这里插入图片描述
在这里插入图片描述


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()

在这里插入图片描述

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()

在这里插入图片描述
在这里插入图片描述


开发记事本软件的菜单

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

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("<Button-3>",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()

在这里插入图片描述


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

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("<Control-n>",lambda event:self.newfile())
        root.bind("<Control-o>",lambda event:self.openfile())
        root.bind("<Control-s>",lambda event:self.savefile())
        root.bind("<Control-q>",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("<Button-3>",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()


文件打包分发(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("<ButtonRelease-1>",self.stopDraw)

        #增加颜色切换的快捷键
        root.bind("<KeyPress-r>",self.kuaijiejian)
        root.bind("<KeyPress-g>",self.kuaijiejian)
        root.bind("<KeyPress-y>",self.kuaijiejian)

    def eventManager(self,event):
        name = event.widget.winfo_name()
        print(name)
        if name=="line":
            self.drawpad.bind("<B1-Motion>",self.myline)
        elif name=="lineArrow":
            self.drawpad.bind("<B1-Motion>",self.mylineArrow)
        elif name=="rect":
            self.drawpad.bind("<B1-Motion>",self.myRect)
        elif name=="pen":
            self.drawpad.bind("<B1-Motion>",self.myPen)
        elif name=="erasor":
            self.drawpad.bind("<B1-Motion>",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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值