单击鼠标绘制矩形[Python]

时间:2012-10-11 10:32:08

标签: python drawing tkinter rectangles

def xaxis(event):
   x1, y1 = (event.x - 1), (event.y - 1)

def yaxis(event):
   x2, y2 = (event.x + 1), (event.y + 1)

def create(event):
   w.create_rectangle(x1,y1,x2,y2,fill='Black')

w = Canvas(root, width=canvas_width, height=canvas_height)
w.config(cursor='cross')
w.pack(expand=YES, fill=BOTH)
w.bind("<Button-1>", xaxis)
w.bind("<ButtonRelease-1>", yaxis)
w.bind("<ButtonRelease-1>", create)

shell说

  

Tkinter回调中的异常回溯(最近一次调用最后一次):
  文件   “/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py”   第1410行,致电       return self.func(* args)文件“/Users/Leo/Desktop/draw.py”,第22行,在创建       w.create_rectangle(x1,y1,x2,y2,fill ='Black')NameError:未定义全局名称'x1'

它认为create函数无法获取其他函数的坐标...

我是这样做的,因为我以后需要坐标!

我希望你能帮助我.. ;-) 谢谢!

3 个答案:

答案 0 :(得分:8)

解决“全局名称'x1'未定义”问题

调试时的一个好的经验法则是假设错误消息说的是实话。在这种情况下,它表示没有名为“x1”的全局变量。所以问问自己“为什么?”。您要么根本不创建“x1”变量,要么创建它不是全局变量。

在您的情况下,当您定义x1,y1,x2和y2时,您将它们创建为局部变量。这是创建变量时python的默认行为。最简单的解决方案是将它们声明为全局:

def xaxis(event):
   global x1, y1
   x1, y1 = (event.x - 1), (event.y - 1)

def yaxis(event):
    global x2, y2
    x2, y2 = (event.x + 1), (event.y + 1)

无关的第二个问题

您的代码中还有另一个问题,即如何进行绑定。请考虑以下代码段:

w.bind("<ButtonRelease-1>", yaxis)
w.bind("<ButtonRelease-1>", create)

您没有创建两个绑定,您正在创建一个绑定,然后用另一个绑定它。但是,您不需要两个绑定。您可以在create函数中调用yaxis函数。

使用面向对象的方法

但是,全局变量通常不是问题的最佳解决方案。如果切换到使用面向对象的方法,则可以将坐标存储为对象的属性。这是一个完整的,有效的例子:

import Tkinter as tk

class ExampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.x = self.y = 0
        self.canvas = tk.Canvas(self, width=400, height=400, cursor="cross")
        self.canvas.pack(side="top", fill="both", expand=True)
        self.canvas.bind("<ButtonPress-1>", self.on_button_press)
        self.canvas.bind("<ButtonRelease-1>", self.on_button_release)

    def on_button_press(self, event):
        self.x = event.x
        self.y = event.y

    def on_button_release(self, event):
        x0,y0 = (self.x, self.y)
        x1,y1 = (event.x, event.y)

        self.canvas.create_rectangle(x0,y0,x1,y1, fill="black")

if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()

拖动鼠标时绘图

如果要在拖动光标时绘制矩形,可以更改程序以在按下按钮时创建矩形。如果您为对象提供唯一的tag或保存画布id,则可以设置鼠标移动事件以使用画布的coords方法调整当前矩形的坐标宾语。我会将其作为练习留给读者,因为它与被问到的问题没有直接关系。

答案 1 :(得分:1)

您只在本地功能中设置了x1等(例如xaxis),因此无法在create中使用它们。您可以重写这些,以便返回所需的结果:

def xaxis(event):
   return (event.x - 1), (event.y - 1) # x1, y1

def yaxis(event):
   return (event.x + 1), (event.y + 1) # x2, y2

def create(event):
   x1, y1 = xaxis(event)
   x2, y2 = yaxis(event)
   w.create_rectangle(x1,y1,x2,y2,fill='Black')

答案 2 :(得分:0)

您正在将x1,x2 ...的结果存储在局部变量中。退出事件处理函数时,这些值将丢失。您必须使用全局变量或专用对​​象来管理事件处理程序。我更喜欢第二种解决方案。

另一个问题是你有两个与Button-Release1绑定的函数。我的解决方案不是绑定yaxis并从create中调用它。可以找到一种更清洁的方法:)

见下面的例子。它应该工作:

from Tkinter import *

root=Tk()

class Handler:

    def __init__(self, w):
        self.w = w
        w.bind("<Button-1>", self.xaxis)
        #w.bind("<ButtonRelease-1>", self.yaxis)
        w.bind("<ButtonRelease-1>", self.create)


    def xaxis(self, event):
        self.x1, self.y1 = (event.x - 1), (event.y - 1)

    def yaxis(self, event):
        self.x2, self.y2 = (event.x + 1), (event.y + 1)

    def create(self, event):
        self.yaxis(event)
        self.w.create_rectangle(self.x1,self.y1,self.x2,self.y2,fill='Black')

w = Canvas(root, width=200, height=200)
w.config(cursor='cross')
w.pack(expand=YES, fill=BOTH)

Handler(w)


root.mainloop()