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

贝壳说

Tkinter 回调 Traceback 中的异常(最近一次调用最后一次):
文件“/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py”,第 1410 行,调用 返回 self。 func(*args) File "/Users/Leo/Desktop/draw.py", line 22, in create w.create_rectangle(x1,y1,x2,y2,fill='Black') NameError: global name 'x1' is没有定义的

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

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

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

4

3 回答 3

9

解决“未定义全局名称'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()

拖动鼠标时绘图

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

于 2012-10-11T10:57:56.553 回答
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')
于 2012-10-11T10:35:39.363 回答
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()
于 2012-10-11T12:01:06.510 回答