0

So, the problem that I face and that I am trying to fix is the following. I am using the second part of the tkinter code from this guy (martineau) here: Selecting an area of an image with a mouse and recording the dimensions of the selection

I have taken the code and made it a callable class like this:

class select_area_class:
    def __call__(self):
        import tkinter as tk
        from PIL import Image, ImageTk 
        
        WIDTH, HEIGHT = 900, 900
        topx, topy, botx, boty = 0, 0, 0, 0

        . . . 

        canvas.bind('<B1-Motion>', update_sel_rect)

        window.mainloop()

The problem is that when this function is called:

def get_mouse_posn(event):
    global topy, topx

    topx, topy = event.x, event.y
    . . . 

(by the way I have erased this command: global topy, topx because it was throwing me an error, so, I have made it like this:

def get_mouse_posn(event):

    topx, topy = event.x, event.y
    . . . 

)

it does not update the main values: topx, topy. So, anywhere I place the mouse inside the widget, I get as initial position the (0,0). I have tried to return event.x, event.y but I cannot figure out how to read the return values from this command:

canvas.bind('<Button-1>', get_mouse_posn)

in order to update the main variables topx, topy and so to make the code work.... I have read both how canvas work (here: https://web.archive.org/web/20201108093851id_/http://effbot.org/tkinterbook/canvas.htm) and how bind works (here: https://web.archive.org/web/20201111211515id_/https://effbot.org/tkinterbook/tkinter-events-and-bindings.htm ), but I cannot find a way to make it work. Any ideas?

just_learning
  • 413
  • 2
  • 11
  • 24
  • 1
    Removing the `global` statement directly causes the values to not get updated outside the function. What is that error you mentioned? – Jan Wilamowski Feb 14 '22 at 09:42
  • Ok, I enabled the global variables. It throws me this error: `File "test_code.py", line 327, in update_sel_rect canvas.coords(rect_id, topx, topy, botx, boty) # Update selection rect. NameError: name 'rect_id' is not defined` but I see that enabling the other global variables and disabling only this: `global rect_id` that it works!! Do I need `rect_id` ? So, the global variables are limited inside the specific class as I understand, right?? – just_learning Feb 14 '22 at 10:04
  • 1
    I don't know if _you_ need `rect_id` but presumably it has a purpose in the code. You may want to be careful with using global variables too, there is probably a different way to implement what you need. – Jan Wilamowski Feb 14 '22 at 10:06
  • 1
    If you have used class, why don't you use *instance variables* instead of *global variables*? – acw1668 Feb 14 '22 at 11:46
  • @acw1668: Can you give me an example? – just_learning Feb 14 '22 at 12:18

1 Answers1

1

Since you have used class, it is better to use instance variables instead of global variables.

Also change get_mouse_posn() and update_sel_rect() to class methods as well.

Below is a simple example based on your posted code:

import tkinter as tk
from PIL import Image, ImageTk

class select_area_class:
    def __call__(self):
        window = tk.Tk()

        WIDTH, HEIGHT = 900, 900
        # use instance variables
        self.topx, self.topy, self.botx, self.boty = 0, 0, 0, 0

        self.canvas = tk.Canvas(window, width=WIDTH, height=HEIGHT)
        self.canvas.pack()

        self.canvas.bind('<Button-1>', self.get_mouse_posn)
        self.canvas.bind('<B1-Motion>', self.update_sel_rect)

        window.mainloop()

    def get_mouse_posn(self, event):
        self.topx, self.topy = self.botx, self.boty = event.x, event.y
        self.rect_id = self.canvas.create_rectangle(self.topx, self.topy, self.botx, self.boty, outline='red')

    def update_sel_rect(self, event):
        self.botx, self.boty = event.x, event.y
        self.canvas.coords(self.rect_id, self.topx, self.topy, self.botx, self.boty)


a = select_area_class()
a()

Note: Is it necessary to make the class callable?

acw1668
  • 40,144
  • 5
  • 22
  • 34