1

I have a canvas. When I right click on it:

  1. It returns me coords where I've clicked, that's ok;
  2. Opens popup menu with some functions, but far away (left - up) and that is a main problem. That's not ok;

I want this menu to open next to the place I've just right clicked (Up-right from the place where mouse clicked).

How should I specify to it where to open this menu or maybe I need to change some attributes?

from tkinter import *
from tkinter import ttk # for Treeview


class Main(Frame):
    def __init__(self, main):
        Frame.__init__(self, main)
        # Vars that will be defined by user:
        self.frame_width = 300
        self.frame_height = 300
        self.canvas_width = 600
        self.canvas_height = 600

        # Flexible widgets when window size alters:
        main.columnconfigure(0, weight=1)
        main.rowconfigure(0, weight=1)

        # Some text
        Label(text='Some text 1').grid(row=0, column=0)
        Label(text='Some text 2').grid(row=1, column=0)
        Label(text='Some text 3').grid(row=2, column=0)
        Label(text='Some text 4').grid(row=3, column=0)
        Label(text='Some text 5').grid(row=4, column=0)

        # Canvas and frame
        canvas_frame = Frame(main, width=self.frame_width, height=self.frame_height, relief='groove')
        canvas_frame.grid(row=1, column=1)
        canvas_frame.grid_propagate(False)
        self.canvas = Canvas(canvas_frame, width = self.canvas_width, height = self.canvas_height,
                        bg='bisque')
        self.canvas.grid(row=0, column=0)

        # (!!!) RIGHT CLICK MENU
        self.rmenu = Menu(self.canvas, tearoff=0, takefocus=0)
        self.rmenu.add_command(label='Add', command=self.hello)
        self.canvas.bind("<ButtonPress-3>", self.popup)

        # Bind
        self.canvas.bind("<ButtonPress-1>", self.scroll_start)
        self.canvas.bind("<B1-Motion>", self.scroll_move)

        # Functions
        self.grid(self.canvas)
    # End of init function.


    # canvas popup menu: --------------------------------------------------
    # (!!!) HERE IS THE POPUP RIGHTCLICK MENU FUNCTIONS
    def popup(self, event):
        self.rmenu.tk_popup(event.x + 40, event.y + 10, entry="0")
        coords_1 = []
        coords_1 += [[event.x, event.y]]
        print(coords_1)

    def hello(self):
        print('hello')

    # grid:  --------------------------------------------------

    def grid(self, canvas):
        for l in range(0, self.canvas_width, 10):
            canvas.create_line([(l, 0), (l, self.canvas_width)], fill='#d9d9d9')
        for l in range(0, self.canvas_height, 10):
            canvas.create_line([(0, l), (self.canvas_height, l)], fill='#d9d9d9')

    # scrolling canvas: ----------------------------------------

    def scroll_start(self, event):
        self.canvas.scan_mark(event.x, event.y)

    def scroll_move(self, event):
        self.canvas.scan_dragto(event.x, event.y, gain=1)



if __name__ == '__main__':
    main = Tk()
    # Making window opens in the centre of the screen
    w = 800
    h = 650
    ws = main.winfo_screenwidth()
    hs = main.winfo_screenheight()
    x = (ws / 2) - (w / 2)
    y = (hs / 2) - (h / 2)
    main.geometry('%dx%d+%d+%d' % (800, 600, x, y))
    #
    Main(main)
    main.mainloop()

All necessary parts I pointed out with (!!!) and uppercase text

martineau
  • 119,623
  • 25
  • 170
  • 301
codY
  • 17
  • 5

2 Answers2

2

Use event.x_root and event.y_root instead of event.x, event.y to get absolute screen coordinates.

self.rmenu.tk_popup(event.x_root + 40, event.y_root + 10, entry="0")

Doc: Events and Bindings


BTW: there is also

x = root.winfo_pointerx()
y = root.winfo_pointery()

which also give absolute screen coordinates for mouse.

(Stackoverflow: Mouse Position Python Tkinter)

furas
  • 134,197
  • 12
  • 106
  • 148
  • there is popular documentation for tkinter: [Events and Bindings](https://effbot.org/tkinterbook/tkinter-events-and-bindings.htm) but sometimes information are incomplete. – furas Nov 05 '19 at 10:21
  • I added also `root.winfo_pointerx(), root.winfo_pointery()` to answer. – furas Nov 05 '19 at 10:24
0

Just use self.rmenu.tk_popup(event.x_root, event.y_root, entry="0"), not self.rmenu.tk_popup(event.x + 40, event.y + 10, entry="0"). That's the bug. Menu requires absolute pointer positions,and event.x,event.y are relative. Hope that's helpful!

rizerphe
  • 1,340
  • 1
  • 14
  • 24
  • It does not helped.. Maybe this information will be helpful in solving a problem : if I event.y + 300 event.x + 300 the menu appears closer to the place where I've clicked. I guess I wrote sth wrong in the Menu attributes or didn't wrote something important at all – codY Nov 05 '19 at 09:43
  • Ok I will check. Sorry, now I'm busy, but I will help as soon as possible – rizerphe Nov 05 '19 at 10:55
  • This won't work. `tk_popup` requires coordinates relative to the whole screen. `event.x` and `event.y` are coordinates relative to the window where the event occurred. – Bryan Oakley Nov 05 '19 at 13:40