Нарисуйте прямоугольник по щелчку мыши [Python]

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 (последний вызов последним):
Файл "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", строка 1410, в файле возврата вызова self.func(*args) "" Users / Leo / Desktop / draw.py ", строка 22, в create w.create_rectangle(x1,y1,x2,y2,fill='Black') NameError: глобальное имя 'x1' не определено

и он думает, что функция создания не может получить координаты других функций...

Я сделал это так, потому что мне нужны координаты позже!

Я надеюсь, что вы можете помочь мне..;-) Спасибо!

3 ответа

Решение

Решение проблемы "глобальное имя '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)

Вы не создаете две привязки, вы создаете одну, а затем перезаписываете ее другой. Однако вам не нужны две привязки. Вы можете вызвать свою функцию yaxis из функции create.

Использование объектно-ориентированного подхода

Однако глобальные переменные обычно не являются лучшим решением проблемы. Если вы переключились на использование объектно-ориентированного подхода, то вы можете сохранить координаты в качестве атрибутов объекта. Вот полный рабочий пример:

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

Рисование при перетаскивании мышью

Если вы хотите нарисовать прямоугольник при перетаскивании курсора, вы можете изменить программу, чтобы создать прямоугольник при нажатии кнопки. Если вы либо присвоите объекту уникальный тег, либо сохраните идентификатор холста, вы можете настроить событие движения мыши, чтобы скорректировать координаты текущего прямоугольника, используя метод координат объекта холста. Я оставлю это как упражнение для читателя, поскольку оно не имеет прямого отношения к заданному вопросу.

Вы только установили 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')

Вы сохраняете результаты x1, x2 ... в локальных переменных. Эти значения теряются при выходе из функции обработчика событий. Вы должны использовать глобальные переменные или выделенный объект для управления обработчиками событий. Я бы предпочел 2-е решение.

Другая проблема заключается в том, что у вас есть две функции, связанные с Button-Release1. Мое решение состоит не в том, чтобы связать yaxis и вызвать его из создания. Более чистый подход можно найти:)

Смотрите пример ниже. Он должен работать:

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()
Другие вопросы по тегам