Tkinter: Draw rectangle using a mouse
The Scrollbars do not show because you grid
them into a Frame (self.sbarv=Scrollbar(self, ...)
) which you do not place into the parent window. You directly grid the Canvas into the parent window though (self.canvas = Canvas(master, ...)
).
What you should do is also put the Canvas in self
and then pack the Frame into the master window using
app = ExampleApp(root)app.pack()
However, when scrolling, the event.x
and event.y
do not represent the correct position on tha canvas anymore, so you should use
self.start_x = self.canvas.canvasx(event.x)self.start_y = self.canvas.canvasy(event.y)
and
curX = self.canvas.canvasx(event.x)curY = self.canvas.canvasy(event.y)
Then, I understand you want to automatically scroll the canvas when the mouse is dragging to one of the borders of the canvas? To do that, you need to check if the mouse is at one of the edges of the canvas and scroll in that direction if it is. You can use something like:
w, h = self.canvas.winfo_width(), self.canvas.winfo_height()if event.x > 0.9*w: self.canvas.xview_scroll(1, 'units') elif event.x < 0.1*w: self.canvas.xview_scroll(-1, 'units')if event.y > 0.9*h: self.canvas.yview_scroll(1, 'units') elif event.y < 0.1*h: self.canvas.yview_scroll(-1, 'units')
So, all that implemented in your code becomes:
import PIL.Imageimport Imageimport ImageTkfrom Tkinter import * class ExampleApp(Frame): def __init__(self,master): Frame.__init__(self,master=None) self.x = self.y = 0 self.canvas = Canvas(self, cursor="cross") self.sbarv=Scrollbar(self,orient=VERTICAL) self.sbarh=Scrollbar(self,orient=HORIZONTAL) self.sbarv.config(command=self.canvas.yview) self.sbarh.config(command=self.canvas.xview) self.canvas.config(yscrollcommand=self.sbarv.set) self.canvas.config(xscrollcommand=self.sbarh.set) self.canvas.grid(row=0,column=0,sticky=N+S+E+W) self.sbarv.grid(row=0,column=1,stick=N+S) self.sbarh.grid(row=1,column=0,sticky=E+W) self.canvas.bind("<ButtonPress-1>", self.on_button_press) self.canvas.bind("<B1-Motion>", self.on_move_press) self.canvas.bind("<ButtonRelease-1>", self.on_button_release) self.rect = None self.start_x = None self.start_y = None self.im = PIL.Image.open("logo.png") self.wazil,self.lard=self.im.size self.canvas.config(scrollregion=(0,0,self.wazil,self.lard)) self.tk_im = ImageTk.PhotoImage(self.im) self.canvas.create_image(0,0,anchor="nw",image=self.tk_im) def on_button_press(self, event): # save mouse drag start position self.start_x = self.canvas.canvasx(event.x) self.start_y = self.canvas.canvasy(event.y) # create rectangle if not yet exist if not self.rect: self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, outline='red') def on_move_press(self, event): curX = self.canvas.canvasx(event.x) curY = self.canvas.canvasy(event.y) w, h = self.canvas.winfo_width(), self.canvas.winfo_height() if event.x > 0.9*w: self.canvas.xview_scroll(1, 'units') elif event.x < 0.1*w: self.canvas.xview_scroll(-1, 'units') if event.y > 0.9*h: self.canvas.yview_scroll(1, 'units') elif event.y < 0.1*h: self.canvas.yview_scroll(-1, 'units') # expand rectangle as you drag the mouse self.canvas.coords(self.rect, self.start_x, self.start_y, curX, curY) def on_button_release(self, event): pass if __name__ == "__main__": root=Tk() app = ExampleApp(root) app.pack() root.mainloop()