Tk Tutorial - 12. Canvas

A canvas widget manages a 2D collection of graphical objects — lines, circles,images, other widgets and more.

Canvas widgets are created using the Canvas function:

canvas = Canvas(parent)

Creating Items

To create a line, the one piece of information you'll need to specify is where the line should be. This is done by using the coordinates of the starting and ending point, expressed as a list of the form x0 y0 x1 y1. The origin (0,0) is at the top left corner of the canvas,with the x value increasing as you move to the right, and the y value increasing as you move down. So to create a line from (10,10) to (200,50), we'd use this code:

canvas.create_line(10, 10, 200, 50)
Let's start our simple sketchpad example.

from tkinter import *
from tkinter import ttk

lastx, lasty = 0, 0

def xy(event):
    global lastx, lasty
    lastx, lasty = event.x, event.y

def addLine(event):
    global lastx, lasty
    canvas.create_line((lastx, lasty, event.x, event.y))
    lastx, lasty = event.x, event.y

root = Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

canvas = Canvas(root)
canvas.grid(column=0, row=0, sticky=(N, W, E, S))
canvas.bind("<Button-1>", xy)
canvas.bind("<B1-Motion>", addLine)

root.mainloop()

Item Attributes

When creating items, you can also specify one or more attributes for the item, that will affect how it is displayed. For example, here we'll specify that the line should be red, and three pixels wide.

canvas.create_line(10, 10, 200, 50, fill='red', width=3)
Like with Tk widgets, changing attributes for canvas items after you've already created them can also be done.

id = canvas.create_line(0, 0, 10, 10, -fill red)
...
canvas.itemconfigure(id, fill='blue', width=2)

Bindings

We've already seen that the canvas widget as a whole, like any other Tk widget, can capture events using the "bind" command.

You can also attach bindings to individual items in the canvas (or groups of them, as we'll see in the next section using tags).

canvas.tag_bind(id, '<1>', ...)
Let's add some code to our sketchpad example to allow changing the drawing color.

color = "black"
def setColor(newcolor):
    global color
    color = newcolor

def addLine(event):
    global lastx, lasty
    canvas.create_line((lastx, lasty, event.x, event.y), fill=color)
    lastx, lasty = event.x, event.y

id = canvas.create_rectangle((10, 10, 30, 30), fill="red")
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("red"))
id = canvas.create_rectangle((10, 35, 30, 55), fill="blue")
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("blue"))
id = canvas.create_rectangle((10, 60, 30, 80), fill="black")
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("black"))

Tags

We've seen that every canvas item has a unique id number, but there is another very useful and powerful way to refer to items on a canvas, and that is using tags.

A tag is just an identifier of your creation, something meaningful to your program. You can attach tags to canvas items; each item can have any number of tags. Unlike item id numbers, which are unique for each item, many items can have the same tag.

What can you do with tags? You can change the color of all items having a specific tag.

Tags are a good way to identify certain types of items in your canvas (items that are part of a drawn line, items that are part of the pallette, etc.).

You can assign tags when creating an item using the "tags" item configuration option. You can add tags later with the "addtag" method, or remove them with the "dtags" method.You can get the list of tags for an item with the "gettags" method, or return a list of item id numbers having the given tag with the "find" command.

>>> c = Canvas(root)
>>> c.create_line(10, 10, 20, 20, tags=('firstline', 'drawing'))
1
>>> c.create_rectangle(30, 30, 40, 40, tags=('drawing'))
2
>>> c.addtag('rectangle', 'withtag', 2)
>>> c.addtag('polygon', 'withtag', 'rectangle')
>>> c.gettags(2)
('drawing', 'rectangle', 'polygon')
>>> c.dtag(2, 'polygon')
>>> c.gettags(2)
('drawing', 'rectangle')	
>>> c.find_withtag('drawing')
(1, 2)
As you can see, things like "withtag" will take either an individual item or a tag; in the latter case, they will apply to all items having that tag (which could be none). The "addtag"and "find" have many other options, allowing you to specify items near a point, overlapping a particular area, and more.

Let's use tags first to put a border around whichever item in our color palette is currently selected.

def setColor(newcolor):
    global color
    color = newcolor
    canvas.dtag('all', 'paletteSelected')
    canvas.itemconfigure('palette', outline='white')
    canvas.addtag('paletteSelected', 'withtag', 'palette%s' % color)
    canvas.itemconfigure('paletteSelected', outline='#999999')

id = canvas.create_rectangle((10, 10, 30, 30), fill="red", tags=('palette', 'palettered'))
id = canvas.create_rectangle((10, 35, 30, 55), fill="blue", tags=('palette', 'paletteblue'))
id = canvas.create_rectangle((10, 60, 30, 80), fill="black", tags=('palette', 'paletteblack', 'paletteSelected'))

setColor('black')
canvas.itemconfigure('palette', width=5)
Let's also use tags to make the current stroke we're drawing appear more visible; when we release the mouse we'll put it back to normal.

def addLine(event):
    global lastx, lasty
    canvas.create_line((lastx, lasty, event.x, event.y), fill=color, width=5, tags='currentline')
    lastx, lasty = event.x, event.y

def doneStroke(event):
    canvas.itemconfigure('currentline', width=1)        

canvas.bind("<B1-ButtonRelease>", doneStroke)

Modifying Items

To delete items, use the "delete" method.To change an item's size and position, you can use the "coords" method; this allows you to provide new coordinates for the item, specified the same way as when you first created the item. Calling this method without a new set of coordinates will return the current coordinates of the item. To move one or more items by a particular horizontal or vertical amount from their current location, you can use the "move"method.
All items are ordered from top to bottom in what's called the stacking order. If an item later in the stacking order overlaps the coordinates of an item below it, the item on top will be drawn on top of the lower item. The "raise" and "lower" methods allow you to adjust an item's position in the stacking order.

Scrolling

In many applications, you'll want the canvas to be larger than what appears on the screen. You can attach horizontal and vertical scrollbars to the canvas in the usual way, via the "xview" and "yview"methods.

The "width" and"height" configuration options for the canvas widget will request the given amount of space from the geometry manager. The "scrollregion" configuration option (e.g. "0 0 1000 1000")tells Tk how large the canvas surface is.

What's going on is that the global "bind" command doesn't know that the canvas is scrolled (it doesn't know the details of any particular widget). So if you've scrolled the canvas down by 50 pixels, and you click on the top left corner, bind will report that you've clicked at (0,0). But we know that because of the scrolling,that position should really be (0,50).

The "canvasx" and "canvasy" methods will translate the position onscreen (which bind is reporting)into the actual point on the canvas, taking into account scrolling.

Here then is our complete example. We probably don't want the palette to be scrolled away when the canvas is scrolled, but we'll leave that for another day.

from tkinter import *
from tkinter import ttk
root = Tk()

h = ttk.Scrollbar(root, orient=HORIZONTAL)
v = ttk.Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
ttk.Sizegrip(root).grid(column=1, row=1, sticky=(S,E))

canvas.grid(column=0, row=0, sticky=(N,W,E,S))
h.grid(column=0, row=1, sticky=(W,E))
v.grid(column=1, row=0, sticky=(N,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)

lastx, lasty = 0, 0

def xy(event):
    global lastx, lasty
    lastx, lasty = canvas.canvasx(event.x), canvas.canvasy(event.y)

def setColor(newcolor):
    global color
    color = newcolor
    canvas.dtag('all', 'paletteSelected')
    canvas.itemconfigure('palette', outline='white')
    canvas.addtag('paletteSelected', 'withtag', 'palette%s' % color)
    canvas.itemconfigure('paletteSelected', outline='#999999')

def addLine(event):
    global lastx, lasty
    x, y = canvas.canvasx(event.x), canvas.canvasy(event.y)
    canvas.create_line((lastx, lasty, x, y), fill=color, width=5, tags='currentline')
    lastx, lasty = x, y

def doneStroke(event):
    canvas.itemconfigure('currentline', width=1)        
        
canvas.bind("<Button-1>", xy)
canvas.bind("<B1-Motion>", addLine)
canvas.bind("<B1-ButtonRelease>", doneStroke)

id = canvas.create_rectangle((10, 10, 30, 30), fill="red", tags=('palette', 'palettered'))
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("red"))
id = canvas.create_rectangle((10, 35, 30, 55), fill="blue", tags=('palette', 'paletteblue'))
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("blue"))
id = canvas.create_rectangle((10, 60, 30, 80), fill="black", tags=('palette', 'paletteblack', 'paletteSelected'))
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("black"))

setColor('black')
canvas.itemconfigure('palette', width=5)
root.mainloop()

Other Item Types

Items of type "line" can actually be a bit fancier than what we've seen.

Items of type "rectangle" we've seen. Items of type "oval" work the same but draw as an oval.Items of type "arc" allow you to draw just a piece of an oval. Items of type "polygon" allow you to draw a closed polygon with any number of sides.

Pictures can be added to canvas widgets, using items of type "bitmap" (for black and white), or type"image" (for full color).

You can add text to a canvas using items of type "text". You have complete control of the font, size,color and more, as well as the actual text that is displayed.

Perhaps most interestingly, you can embed other widgets (which would include a frame which itself contains other widgets) into a canvas using an item of type "window". When we do this, the canvas in effect acts as a geometry manager for those other widgets. This capability raises all kinds of possibilities for your application.

from: http://www.tkdocs.com/tutorial/canvas.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值