Python tkinter工作时的基本图像编辑,但拖动鼠标

时间:2016-02-22 23:52:00

标签: python image canvas tkinter tkinter-canvas

以下代码生成一个带有图像的漂亮Canvas,我可以在它上面绘制一个正方形。然而: a)我无法让Canvas不滚动。 b)我只希望图像显示而不是其他任何东西,并且无法正确显示尺寸

正如您将看到的,我甚至试图停止滚动但它不能一直工作。此外,即使我将三个(根,画布和图像)的大小设置为相同,图像也永远不会与Canvas和窗口完全对齐。

这是代码(部分取自另一个示例,其中一些部分被注释掉):

try:
    from PIL import Image
except ImportError:
    import Image
from PIL import ImageTk


try:
    import Tkinter as tk  # Python2
except ImportError:
    import tkinter as tk  # Python3s
import Tkinter
from Tkinter import *
import PIL as PILAll


class ExampleApp(Frame):
    def __init__(self,master):
        Frame.__init__(self,master=None)
        self.x = 0
        self.y = 0
        self.canvas = Canvas(self,  cursor="cross", width=640, height=480, confine=True, scrollregion=(10, 10, 10, 10), relief="groove", bg="blue")# and I have experimented with a few other options

        #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.config(scrollregion=self.canvas.bbox(ALL))
        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.canvas.bind("<Leave>", self.on_button_leave)
        self.canvas.bind("<Enter>", self.on_button_enter)
        self.canvas.bind("<Double-Button-1>",     self.on_double_click)
        self.canvas.create_line(0, 0, 200, 100)
        self.canvas.create_line(0, 100, 200, 0, fill="red", dash=(4, 4))
        self.canvas.create_rectangle(50, 25, 150, 75, fill="blue")
        self.rect = None
        self.text = None
        self.start_x = None
        self.start_y = None

        self.im = PILAll.Image.open("../../" + "image6.JPG")
        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)


    out_of_scope = 1

    def on_button_leave(self, event):
        self.out_of_scope = 2
        print "out_of_scope....", self.out_of_scope

    def on_button_enter(self, event):
        print("entering...")
        self.out_of_scope = 1

    def on_double_click(self, event):
        print("double click")

    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:
            if self.out_of_scope == 1:
                self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, outline='blue', fill='yellow') #since it's only created once it always remains at the bottom

    def get_out_of_scope(self, x, y):
        return self.out_of_scope

    def on_move_press(self, event):
        curX = self.canvas.canvasx(event.x)
        curY = self.canvas.canvasy(event.y)
        var=self.get_out_of_scope(event.x, event.y)
        print(var, event.x, event.y)
        if var == 1:
            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):
        print(event.x, event.y)
        pass

root=Tk()
root.geometry("640x480")
app = ExampleApp(root)
app.grid()
root.mainloop()

1 个答案:

答案 0 :(得分:1)

我认为您的代码会因reviewed而受益,但我会尝试将自己限制在这个问题上......

如果canvas需要与图片大小相同,为什么用width=640, height=480构建它?你可以进一步计算出图像的宽度和高度:

    self.im = PILAll.Image.open("../../" + "image6.JPG")
    self.wazil,self.lard=self.im.size

(有趣的变量名称选择btw)所以,如果self.wazilself.lard代表图像的宽度和高度,为什么不让它成为画布的宽度和高度?

    self.im = PILAll.Image.open("../../" + "image6.JPG")
    self.wazil,self.lard=self.im.size
    self.canvas = Canvas(self, width=self.wazil, height=self.lard) #, ...) 

然后画布将是正确的大小,但根窗口仍然强制自己 640x480

root.geometry("640x480")

但由于小部件会自动扩展到内容,您只需对该行进行注释,它的大小应该正确。

#root.geometry("640x480")

我应该注意到,我正在经历一些非常奇怪的行为,关于图像的位置是3像素太高,左边3像素,用图像绘制图像:

self.canvas.create_image(3,3,anchor="nw",image=self.tk_im)

为我修好了,但我不知道为什么......

至于滚动,您删除了有关滚动条的部分,但是您在on_move_press中留下了这些内容:

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

这是偶尔滚动画布的代码部分(当我尝试调整窗口大小时发生),所以你可以再次对该部分进行评论,它不应该再滚动。

最后一个与问题无关的注释,你有:

def __init__(self,master):
    Frame.__init__(self,master=None)

但我很确定你的意思是:

def __init__(self,master=None):
    Frame.__init__(self,master)

因为您需要主参数的第一种方式,但不要将其传递给Frame.__init__。当Frame.__init__收到None的主文件时,它只使用Tk实例,在您的情况下是相同的,但如果您使用任何其他主文件,则会导致非常奇怪的问题。