03-tkinter-Canve画布使用

1. 概述

1.1 案例说明

本案例是完成一个简易的画板工具,通过本案例的练习来熟悉单选、复选、列表以及组合框的使用。
该简易的画板工具具备基本的绘图、清除以及颜色设置功能。如下面图片所示:


image.png

2. 菜单以及画布的基本使用

照旧,在进行案例代码编写前,先花点时间完成下面2个代码段的练习,熟悉这些组件的使用方法。

2.1 menu菜单

import tkinter
window = tkinter.Tk()
window.title('my window')
window.geometry('200x150')

l = tkinter.Label(window, text='', bg='pink', width=10)
l.pack()
counter = 0


def do():
    global counter
    l.config(text='do ' + str(counter))
    counter += 1


# 创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tkinter.Menu(window)
# 定义一个空菜单单元
filemenu = tkinter.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为`File`,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='File', menu=filemenu)
# 在`File`中加入`New`的小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。
# 如果点击这些单元, 就会触发`do`的功能
filemenu.add_command(label='New', command=do)
# 在`File`中加入`Open`小菜单
filemenu.add_command(label='Open', command=do)
# 在`File`中加入`Save`小菜单
filemenu.add_command(label='Save', command=do)
# 这里是一条分割线
filemenu.add_separator()
# 在`File`中加入`Exit`小菜单,对应命令为`window.quit`退出
filemenu.add_command(label='Exit', command=window.quit)

# 子菜单定义,`File`上创建一个空的菜单
submenu = tkinter.Menu(filemenu)
# 给放入的菜单`submenu`命名为`Import`
filemenu.add_cascade(label='Import', menu=submenu, underline=0)
# 这里和上面也一样,在`Import`中加入一个小菜单命令`Submenu1`
submenu.add_command(label="Submenu1", command=do)
submenu.add_command(label="Submenu2", command=do)

editmenu = tkinter.Menu(menubar, tearoff=0)
menubar.add_cascade(label='Edit', menu=editmenu)
editmenu.add_command(label='Cut', command=do)
editmenu.add_command(label='Copy', command=do)
editmenu.add_command(label='Paste', command=do)


window.config(menu=menubar)
window.mainloop()

运行结果如下:


image.png

2.2 canve画布

import tkinter
app = tkinter.Tk()
app.title('my window')
app.geometry('200x200')
# 创建画布,并设置背景颜色,以及画布长宽
canvas = tkinter.Canvas(app, bg='#b9b9f9', height=150, width=200)
# 定义图片
image_file = tkinter.PhotoImage(file='1.gif')
# 将图片放置在画布上
image = canvas.create_image(150, 10,
                            anchor='nw',  # 把图片的左上角作为锚定点
                            image=image_file)
x0, y0, x1, y1 = 50, 50, 80, 80
# 绘制直线,从(50, 50)到(50, 80)
line = canvas.create_line(50, 80, 140, 80)
# 绘制圆形
oval = canvas.create_oval(50, 50, 80, 80, fill='pink')
# 绘制扇形
arc = canvas.create_arc(x0+30, y0+30, x1+30, y1+30, start=0, extent=180)
# 绘制矩形
rect = canvas.create_rectangle(50, 30, 100+50, 30+20)
canvas.pack()


def moveit():
    canvas.move(oval, 2, 0)


b = tkinter.Button(app, text='move', command=moveit).pack()
app.mainloop()

运行结果如下:


image.png

3. 案例代码实现

import tkinter
from tkinter import colorchooser


app = tkinter.Tk()
app.title('My Paint')
app['width'] = 800
app['height'] = 600

# 控制是否允许画图的变量,1:允许,0:不允许
yesno = tkinter.IntVar(value=0)
# 控制画图类型的变量,1:曲线,2:直线,3:矩形
what = tkinter.IntVar(value=1)
# 记录鼠标位置的变量
X = tkinter.IntVar(value=0)
Y = tkinter.IntVar(value=0)
# 前景色
foreColor = '#000000'
backColor = '#FFFFFF'
# 创建画布
image = tkinter.PhotoImage()
canvas = tkinter.Canvas(app, bg='white', width=800, height=600)
canvas.create_image(800, 600, image=image)


# 鼠标左键单击,允许画图
def onLeftButtonDown(event):
    yesno.set(1)
    X.set(event.x)
    Y.set(event.y)


canvas.bind('<Button-1>', onLeftButtonDown)

# 记录最后绘制图形的id
lastDraw = 0


# 按住鼠标左键移动,画图
def onLeftButtonMove(event):
    if yesno.get() == 0:
        return
    if what.get() == 1:
        # 使用当前选择的前景色绘制曲线
        canvas.create_line(X.get(), Y.get(), event.x, event.y, fill=foreColor)
        X.set(event.x)
        Y.set(event.y)
    elif what.get() == 2:
        # 绘制直线,先删除刚刚画过的直线,再画一条新的直线
        global lastDraw
        try:
            canvas.delete(lastDraw)
        except Exception as e:
            pass
        lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y,
                                      fill=foreColor)
    elif what.get() == 3:
        # 绘制矩形,先删除刚刚画过的矩形,再画一个新的矩形
        # global lastDraw
        lastDraw
        try:
            canvas.delete(lastDraw)
        except Exception as e:
            pass
        lastDraw = canvas.create_rectangle(X.get(), Y.get(), event.x, event.y,
                                           fill=backColor, outline=foreColor)


canvas.bind('<B1-Motion>', onLeftButtonMove)


# 鼠标左键抬起,不允许画图
def onLeftButtonUp(event):
    if what.get() == 2:
        # 绘制直线
        canvas.create_line(X.get(), Y.get(), event.x, event.y, fill=foreColor)
    elif what.get() == 3:
        # 绘制矩形
        canvas.create_rectangle(X.get(), Y.get(), event.x, event.y,
                                fill=backColor, outline=foreColor)
    yesno.set(0)
    global lastDraw
    lastDraw = 0


canvas.bind('<ButtonRelease-1>', onLeftButtonUp)

# 创建菜单
menu = tkinter.Menu(app, tearoff=0)


# 添加菜单,清除
def clear():
    for item in canvas.find_all():
        canvas.delete(item)


menu.add_command(label='Clear', command=clear)
# 添加分割线
menu.add_separator()
# 创建子菜单,用来选择绘图类型
menuType = tkinter.Menu(menu, tearoff=0)


def draw_curve():
    what.set(1)
    print(what.get())


menuType.add_command(label='Curve', command=draw_curve)


def draw_line():
    what.set(2)


menuType.add_command(label='Line', command=draw_line)


def draw_rectangle():
    what.set(3)


menuType.add_command(label='Rectangle', command=draw_rectangle)
menuType.add_separator()


# 选择前景色
def chooseForeColor():
    global foreColor
    foreColor = tkinter.colorchooser.askcolor()[1]


menuType.add_command(label='Choose Foreground Color', command=chooseForeColor)


# 选择背景色
def chooseBackColor():
    global backColor
    backColor = tkinter.colorchooser.askcolor()[1]


menuType.add_command(label='Choose Background Color', command=chooseBackColor)
menu.add_cascade(label='Type', menu=menuType)


# 鼠标右键抬起,弹出菜单
def onRightButtonUp(event):
    menu.post(event.x_root, event.y_root)


canvas.bind('<ButtonRelease-3>', onRightButtonUp)
canvas.pack(fill=tkinter.BOTH, expand=tkinter.YES)

app.mainloop()


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

推荐阅读更多精彩内容

  • 大雪纷飞中,盘点一年来的收获似乎还在昨天,雪未到,今天已是2019最后一天,一边惊叹光阴匆匆飞逝,一边着手...
    小水月阅读 532评论 0 3
  • 20170701更换使用64位日文Windows7版,Office2007的配置笔记本,安装CPC离线客户端,希望...
    simtech2win阅读 5,798评论 0 0
  • 两只老虎跑得快, 一群鸭子下河里。 窗后风吹草动见, 门前大桥下小狗跳。 远望山谷不见边, 近望天空易看见。 记念...
    王密亮阅读 409评论 0 1