59848
**実現したいこと**  
異なるCanvasウィジット間でドラッグアンドドロップを実現する。

**やろうとしていること**  
マウスイベントを親ウィンドウでバインドし、その座標情報からCanvasウィジット上にある座標かを判断し、Canvasウィジット上の座標に変換して、各Canvas内のオブジェクトを操作する。

**現在の問題点・試したこと**  
該当するCanvasウィジット内の有効な座標かどうかを判断したく、各Canvasウィジットのメソッドcanvasx,canvasyを取得して判断しようとしました。  
eventで対象ウィジットの情報が得られたため、どのウィジットでのイベントかは判断できましたが、マウス移動、マウスリリース時では、その移動先のウィジットの情報が得られません。

Canvasウィジット自体の親ウィンドウ上の座標が分かれば、判断できると思うのですが、座標の取得方法が分かりません。  
ご存知の方がいらっしゃればご教示お願い致します。

```

    #! /usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import tkinter as tk
    from tkinter import ttk
    
    class CreateScreen(object):
        def __init__(self):
            self.screen_w = 800
            self.screen_h = 300
            self.dlg_pos_x = 10
            self.dlg_pos_y = 10
    
            return super().__init__()
    
        def createMainWindow(self):
    
            self.MainWindow = ttk.tkinter.Tk() 
    
            geo_string = str(self.screen_w) + "x" + str(self.screen_h) + "+" + str(self.dlg_pos_x)  + "+" + str(self.dlg_pos_y) 
    
            self.MainWindow.geometry(geo_string) 
    
            _InFrame_ = tk.Frame(
                self.MainWindow,
                width = 300,
                height = 200,
                )
    
            self._Canvas_A_ = tk.Canvas(
                _InFrame_,
                bg = 'red'
                )
    
            self._Canvas_B_ = tk.Canvas(
                _InFrame_,
                bg = 'blue'
                )
            _InFrame_.pack()
            self._Canvas_A_.pack(side = tk.LEFT)
            self._Canvas_B_.pack(side = tk.LEFT)
    
            self.MainWindow.bind('<Button-1>',self.MainWindow_left_click)
            self.MainWindow.bind('<B1-Motion>',self.MainWindow_drag_mouse_move_on)
            self.MainWindow.bind('<ButtonRelease-1>',self.MainWindow_mouse_release)
    
            return self.MainWindow
    
        def MainWindow_left_click(self,event):
            if event.widget == self._Canvas_A_:
                x = self._Canvas_A_.canvasx(event.x)
                y = self._Canvas_A_.canvasx(event.y)
                print('_Canvas_A_(Clicled):',x,y)
            if event.widget == self._Canvas_B_:
                x = self._Canvas_B_.canvasx(event.x)
                y = self._Canvas_B_.canvasx(event.y)
                print('_Canvas_B_(Clicled):',x,y)
    
            return
    
        def MainWindow_drag_mouse_move_on(self,event):
            if event.widget == self._Canvas_A_:
                x = self._Canvas_A_.canvasx(event.x)
                y = self._Canvas_A_.canvasx(event.y)
                print('_Canvas_A_(move):',x,y)
            if event.widget == self._Canvas_B_:
                x = self._Canvas_B_.canvasx(event.x)
                y = self._Canvas_B_.canvasx(event.y)
                print('_Canvas_B_(move):',x,y)
            return
    
        def MainWindow_mouse_release(self,event):
            if event.widget == self._Canvas_A_:
                x = self._Canvas_A_.canvasx(event.x)
                y = self._Canvas_A_.canvasx(event.y)
                print('_Canvas_A_(release):',x,y)
            if event.widget == self._Canvas_B_:
                x = self._Canvas_B_.canvasx(event.x)
                y = self._Canvas_B_.canvasx(event.y)
                print('_Canvas_B_(release):',x,y)
            return
    
    if __name__ == '__main__':
        screen_obj = CreateScreen()
        #testobj = tkTest.CreateScreen()
    
        MainWindow_obj = screen_obj.createMainWindow()
    
        #testobj._TemplateDialog(MainWindow_obj)
    
        MainWindow_obj.mainloop()
    
```
CC BY-SA 4.0
2019-10-21T04:41:49.340
59835
2020-07-29T23:01:45.147
2019-10-21T07:08:41.123
3060
32891
question
python tkinter
Python tk ウィジット上の座標を判断したい
自己解決しました。  
他にスマートな書き方があれば、回答をお願いします。

Canvasのwinfo_rootx()およびwinfo_rooty()でウィンドウ上の座標が得られます。  
さらにCanvasのwidth,heightの情報が得られます。  
これらの情報により、各々のCanvasの座標範囲を求め、eventで与えられるウィンドウ上の座標x_root、y_rootが座標範囲に入っているかで判断できました。  
これであとは、Canvas内座標により対象のオブジェクトを判断すれば良いようです。

```

    #! /usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import tkinter as tk
    from tkinter import ttk
    
    class CreateScreen(object):
        def __init__(self):
            self.screen_w = 800
            self.screen_h = 300
            self.dlg_pos_x = 10
            self.dlg_pos_y = 10
    
            return super().__init__()
    
        def createMainWindow(self):
    
            self.MainWindow = ttk.tkinter.Tk() 
    
            geo_string = str(self.screen_w) + "x" + str(self.screen_h) + "+" + str(self.dlg_pos_x)  + "+" + str(self.dlg_pos_y) 
    
            self.MainWindow.geometry(geo_string) 
    
            _InFrame_ = tk.Frame(
                self.MainWindow,
                width = 300,
                height = 200,
                )
    
            self._Canvas_A_ = tk.Canvas(
                _InFrame_,
                bg = 'red'
                )
    
            self._Canvas_B_ = tk.Canvas(
                _InFrame_,
                bg = 'blue'
                )
            _InFrame_.pack()
            self._Canvas_A_.pack(side = tk.LEFT)
            self._Canvas_B_.pack(side = tk.LEFT)
    
            self.MainWindow.bind('<Button-1>',self.MainWindow_left_click)
            self.MainWindow.bind('<B1-Motion>',self.MainWindow_drag_mouse_move_on)
            self.MainWindow.bind('<ButtonRelease-1>',self.MainWindow_mouse_release)
    
            return self.MainWindow
    
        def canvas_coords(self,canvas):
            sx = x = int(canvas.winfo_rootx())
            sy = y = int(canvas.winfo_rooty())
            w = int(canvas['width'])
            h = int(canvas['height'])
            ex = sx + w - 1
            ey = sy + h - 1
    
            return (sx,sy,ex,ey)
    
        def chk_canvas_coords(self,canvas,point):
            _canvas_coords = self.canvas_coords(canvas)
    
            SX = X = 0
            SY = Y = 1
            EX = 2
            EY = 3
    
            if ((point[X] >=_canvas_coords[SX] and point[X] <=_canvas_coords[EX])
                and (point[Y] >=_canvas_coords[SY] and point[Y] <=_canvas_coords[EY])):
                return True
    
            return False
    
        def MainWindow_left_click(self,event):
            x, y = event.x_root, event.y_root
            if self.chk_canvas_coords(self._Canvas_A_,(x,y)):
                print('_Canvas_A_:Left_clicked')
            if self.chk_canvas_coords(self._Canvas_B_,(x,y)):
                print('_Canvas_B_:Left_clicked')
    
            return
    
        def MainWindow_drag_mouse_move_on(self,event):
            x, y = event.x_root, event.y_root
            if self.chk_canvas_coords(self._Canvas_A_,(x,y)):
                print('_Canvas_A_:move_on')
            if self.chk_canvas_coords(self._Canvas_B_,(x,y)):
                print('_Canvas_B_:move_on')
            return
    
        def MainWindow_mouse_release(self,event):
            x, y = event.x_root, event.y_root
            if self.chk_canvas_coords(self._Canvas_A_,(x,y)):
                print('_Canvas_A_:release')
            if self.chk_canvas_coords(self._Canvas_B_,(x,y)):
                print('_Canvas_B_:release')
            return
    
    if __name__ == '__main__':
        screen_obj = CreateScreen()
        #testobj = tkTest.CreateScreen()
    
        MainWindow_obj = screen_obj.createMainWindow()
    
        #testobj._TemplateDialog(MainWindow_obj)
    
        MainWindow_obj.mainloop()
    
```
CC BY-SA 4.0
2019-10-21T08:39:20.480
59848
2019-10-21T08:39:20.480
32891
59835
answer