简体   繁体   English

Tkinter:使用鼠标绘制矩形

[英]Tkinter: Draw rectangle using a mouse

Please, help me to resolve this problem. 请帮我解决这个问题。

I want to allow the user to draw a random rectangle around a specific region of interest in a picture using the mouse ( by clicking the right or left button of the mouse until he releases it). 我想让用户使用鼠标在图片中的特定感兴趣区域周围绘制一个随机矩形(通过单击鼠标的右或左按钮,直到他释放它)。

I deal with large images (images larger than the resolution of my screen, such as this one ), so the user needs to scroll the window in order to be able to see the picture fully. 我处理大量的图像(图像比我的屏幕,分辨率越大,如这一个 ),所以用户需要滚动窗口,以便能够完全看到的景象。

Here is the code I tried just to display a large picture, but I have no idea on how to allow the user to draw using his mouse a rectangle over an object (say a person in a picture): 这是我试图显示大图片的代码,但我不知道如何允许用户使用鼠标在对象上绘制一个矩形(比如图片中的某个人):

from Tkinter import *
import Image,ImageTk

root=Tk()
canv=Canvas(root,relief=SUNKEN)

sbarv=Scrollbar(root,orient=VERTICAL)
sbarh=Scrollbar(root,orien=HORIZONTAL)

sbarv.config(command=canv.yview)
sbarh.config(command=canv.xview)

canv.config(yscrollcommand=sbarv.set)
canv.config(xscrollcommand=sbarh.set)

canv.grid(row=0,column=0,sticky=N+S+E+W)
sbarv.grid(row=0,column=1,sticky=N+S)

sbarh.grid(row=1,column=0,sticky=E+W)


im=Image.open("image.jpg")
width,height=im.size
canv.config(scrollregion=(0,0,width,height))
im2=ImageTk.PhotoImage(im)
imgtag=canv.create_image(0,0,anchor="nw",image=im2)

root.mainloop()

EDIT 1: 编辑1:

  • The rectangle must not be filled. 不得填充矩形。 I mean I want to draw only its 4 lines (segments) but it must be empty inside, I want to draw only its contours in one pixel width. 我的意思是我只想绘制它的4行(段),但它必须是空的,我想只绘制一个像素宽度的轮廓。

  • I also want to draw as the cursor is moving (dragging) not after button release. 我也想在光标移动(拖动)时绘制,而不是在按钮释放后。

  • Also, note that the rectangle to draw may be a long one, I mean the vertical scroll-bar will need to move down to be able to delimitate the whole object of interest (let's say it is a person) 另外,请注意要绘制的矩形可能很长,我的意思是垂直滚动条需要向下移动以便能够划分整个感兴趣的对象(假设它是一个人)

Any help will be highly appreciated. 任何帮助将受到高度赞赏。

Thank you very much in advance 非常感谢你提前

EDIT 2: 编辑2:

Following the link given to me above, I coded this. 按照上面给出的链接,我编写了这个。 My problem is that the scroll-bars do not appear . 我的问题是滚动条没有出现 May be someone could tell me why ? 可能有人可以告诉我为什么?

Note that in this code, I resolved the first and second problems highlighted in EDIT 1 : 请注意,在此代码中,我解决了编辑1中突出显示的第一个和第二个问题:

import PIL.Image
import Image
import ImageTk
from Tkinter import *    


class ExampleApp(Frame):
    def __init__(self,master):
        Frame.__init__(self,master=None)
        self.x = self.y = 0
        self.canvas = Canvas(master,  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 = event.x
        self.start_y = event.y

        # create rectangle if not yet exist
        #if not self.rect:
        self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, fill="")

    def on_move_press(self, event):
        curX, curY = (event.x, event.y)

        # 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)
    root.mainloop()

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. 滚动条不显示,因为您将它们grid化为一个框架( self.sbarv=Scrollbar(self, ...) ),您不将其放入父窗口。 You directly grid the Canvas into the parent window though ( self.canvas = Canvas(master, ...) ). 您可以直接将Canvas网格化到父窗口( 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 你应该做的也是将Canvas放入self ,然后使用框架将框架打包到主窗口

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 但是,在滚动时, event.xevent.y不再代表画布上的正确位置,因此您应该使用

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.Image
import Image
import ImageTk
from 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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM