From Vasilis.Vlachoudis at cern.ch Sun Nov 4 14:37:29 2018 From: Vasilis.Vlachoudis at cern.ch (Vasilis Vlachoudis) Date: Sun, 4 Nov 2018 19:37:29 +0000 Subject: [Tkinter-discuss] Text drag&drop In-Reply-To: <0BC70B5D93E054469872FFD0FE07220E026A56B4D4@CERNXCHG53.cern.ch> References: <0BC70B5D93E054469872FFD0FE07220E026A56B4D4@CERNXCHG53.cern.ch> Message-ID: <0BC70B5D93E054469872FFD0FE07220E026A579E3E@CERNXCHG53.cern.ch> Hi all, answering to my own email :) #2. I found out my mistake why the Label doesn't appear on the second window the "event" that it is passed to the dnd_motion is the event referring to the original window and not the target one. So instead of using the event.x, event.y I need to use the root coordinates and I convert them to local ones x = event.x_root - self.winfo_rootx() y = event.y_root - self.winfo_rooty() self.dnd_item.place(x=x, y=y) #1. However I cannot get rid of the #1. I've tried to subclass the DndHandler() especially the on_motion() method to delete the text anchor (dirty hack) after looking at the text.tcl as well deleting the selection and calling the CancelRepeat to avoid the auto-scrolling, but nothing worked ok. Is there a way to tell the Text() to stop the selection? class MyDndHandler(Dnd.DndHandler): def __init__(self, source, event): super().__init__(source, event) anchor = self.source.tk.call("tk::TextAnchor", self.source._w) self.source.mark_unset(anchor) def on_motion(self, event): super().on_motion(event) anchor = self.source.tk.call("tk::TextAnchor", self.source._w) self.source.mark_unset(anchor) # if self.target is not self.source: self.source.tk.call("tk::CancelRepeat") # self.source.tag_remove(tk.SEL, "1.0", tk.END) return "break" def dnd_start(source, event): h = MyDndHandler(source, event) if h.root: return h else: return None Vasilis ________________________________________ From: Tkinter-discuss [tkinter-discuss-bounces+vasilis.vlachoudis=cern.ch at python.org] on behalf of Vasilis Vlachoudis [Vasilis.Vlachoudis at cern.ch] Sent: Wednesday, October 31, 2018 15:27 To: tkinter-discuss at python.org Subject: [Tkinter-discuss] Text drag&drop Hi all, moving from Canvas() to Text() I wanted to re-implement the same drag&drop functionality I have. I created a small test program show my problem(s). I am creating two, Toplevel windows with MyText() inside. The MyText extends the Text and adds a drag&drop. For demonstration I've binded on the Control-Button-1 the starting of the drag action it creates a "floating" Label() with the selected text, which is placed at the mouse position. Now the problems: 1. The selection on the "drag" window keeps changing as I move the mouse. The selection is changing as if there was a grab_set() even if the cursor is on the second window. 2. If I drag the mouse on the second window, despite the Label is created() it doesn't show it. How can I correct those problems? Many thanks in advance Vasilis import tkinter as tk import tkinter.dnd as Dnd class MyText(tk.Text): def __init__(self, master, *kw, **kwargs): super().__init__(master, *kw, **kwargs) self.bind("", self.button1) self.dnd_text = None # ---------------------------------------------------------------------- def button1(self, event): Dnd.dnd_start(text1, event) self.dnd_text = text1.get(tk.SEL_FIRST, tk.SEL_LAST) # ---------------------------------------------------------------------- def dnd_accept(self, source, event): return self # ---------------------------------------------------------------------- def dnd_enter(self, source, event): self.focus_set() self.dnd_item = tk.Label(self, text=source.dnd_text, border=2, relief=tk.RAISED) self.dnd_motion(source, event) # ---------------------------------------------------------------------- def dnd_leave(self, source, event): self.dnd_item.place_forget() self.dnd_item = None # ---------------------------------------------------------------------- def dnd_motion(self, source, event): self.dnd_item.place(x=event.x, y=event.y) # ---------------------------------------------------------------------- def dnd_end(self, target, event): if self.dnd_item: self.dnd_item.place_forget() self.dnd_item = None self.dnd_text = None # ---------------------------------------------------------------------- # Object has been dropped here # ---------------------------------------------------------------------- def dnd_commit(self, source, event): if self.dnd_item: self.dnd_item.place_forget() self.dnd_item = None if source.dnd_text is None: return self.insert(tk.CURRENT, source.dnd_text) self.dnd_text = None root=tk.Tk() root.title("Top1") text1 = MyText(root) text1.pack(fill=tk.BOTH, expand=tk.YES) for i in range(1000): text1.insert(tk.END, "%d The quick brown fox jumps over the lazy dog's tail\n"%(i)) top2 = tk.Toplevel(root) top2.title("Top2") text2 = MyText(top2) text2.pack(fill=tk.BOTH, expand=tk.YES) root.mainloop() _______________________________________________ Tkinter-discuss mailing list Tkinter-discuss at python.org https://mail.python.org/mailman/listinfo/tkinter-discuss From klappnase at web.de Sun Nov 4 16:56:25 2018 From: klappnase at web.de (Michael Lange) Date: Sun, 4 Nov 2018 22:56:25 +0100 Subject: [Tkinter-discuss] Text drag&drop In-Reply-To: <0BC70B5D93E054469872FFD0FE07220E026A579E3E@CERNXCHG53.cern.ch> References: <0BC70B5D93E054469872FFD0FE07220E026A56B4D4@CERNXCHG53.cern.ch> <0BC70B5D93E054469872FFD0FE07220E026A579E3E@CERNXCHG53.cern.ch> Message-ID: <20181104225625.6d6159213af74f6f1b2e10b6@web.de> Hi, On Sun, 4 Nov 2018 19:37:29 +0000 Vasilis Vlachoudis wrote: (...) > #1. However I cannot get rid of the #1. I've tried to subclass the > #DndHandler() > especially the on_motion() method to delete the text anchor (dirty > hack) after looking at the text.tcl as well deleting the selection and > calling the CancelRepeat to avoid the auto-scrolling, but nothing > worked ok. Is there a way to tell the Text() to stop the selection? I think you could add something like this to DnDHandler.__init__() : def _return_break(widget, event): return 'break' self._id = widget.bind('') widget.bind('', _return_break) which should remove the motion-selection binding and then restore it after the dnd operation has finished by adding self.initial_widget.bind('', self._id) to the end of DnDHandler.finish() (untested however). Regards Michael .-.. .. ...- . .-.. --- -. --. .- -. -.. .--. .-. --- ... .--. . .-. "The combination of a number of things to make existence worthwhile." "Yes, the philosophy of 'none,' meaning 'all.'" -- Spock and Lincoln, "The Savage Curtain", stardate 5906.4 From Vasilis.Vlachoudis at cern.ch Mon Nov 5 02:39:33 2018 From: Vasilis.Vlachoudis at cern.ch (Vasilis Vlachoudis) Date: Mon, 5 Nov 2018 07:39:33 +0000 Subject: [Tkinter-discuss] Text drag&drop In-Reply-To: <20181104225625.6d6159213af74f6f1b2e10b6@web.de> References: <0BC70B5D93E054469872FFD0FE07220E026A56B4D4@CERNXCHG53.cern.ch> <0BC70B5D93E054469872FFD0FE07220E026A579E3E@CERNXCHG53.cern.ch>, <20181104225625.6d6159213af74f6f1b2e10b6@web.de> Message-ID: <0BC70B5D93E054469872FFD0FE07220E026A57A0EE@CERNXCHG53.cern.ch> Thanks Michael, looking at the text.tcl I saw that I need to bind() also the "B1-Enter" and "B1-Leave" since they are responsible for the AutoRepeat window scroll once you exit the window. In order not to lose the auto-scroll I've duplicated the functionality copying from text.tcl and removing the selection auto repeat like this ... self.bind('', self.autoRepeat) self.bind('', self.cancelRepeat) ... def cancelRepeat(self, event=None): if self._autoId: self.after_cancel(self._autoId) self._autoId = None return "break" def autoRepeat(self, event=None): self._autoId = None if not self.winfo_exists(): return "break" if event is None: x, y = self._autoPos else: # Unfortunatelly the scroll is fixed from the first time it exits x, y = self._autoPos = event.x, event.y # Something like this would be more dynamic, but it doesn't work # x = self.winfo_pointerx() - self.winfo_rootx() # y = self.winfo_pointery() - self.winfo_rooty() if y > self.winfo_height(): self.yview(tk.SCROLL, 1+y-self.winfo_height(), "pixels") elif y < 0: self.yview(tk.SCROLL, -1+y, "pixels") elif x > self.winfo_width(): self.xview(tk.SCROLL, 2, tk.UNITS) elif x < 0: self.xview(tk.SCROLL, -2, tk.UNITS) else: return "break" self._autoId = self.after(50, self.autoRepeat) return "break" Vasilis ________________________________________ From: Tkinter-discuss [tkinter-discuss-bounces+vasilis.vlachoudis=cern.ch at python.org] on behalf of Michael Lange [klappnase at web.de] Sent: Sunday, November 04, 2018 22:56 To: tkinter-discuss at python.org Subject: Re: [Tkinter-discuss] Text drag&drop Hi, On Sun, 4 Nov 2018 19:37:29 +0000 Vasilis Vlachoudis wrote: (...) > #1. However I cannot get rid of the #1. I've tried to subclass the > #DndHandler() > especially the on_motion() method to delete the text anchor (dirty > hack) after looking at the text.tcl as well deleting the selection and > calling the CancelRepeat to avoid the auto-scrolling, but nothing > worked ok. Is there a way to tell the Text() to stop the selection? I think you could add something like this to DnDHandler.__init__() : def _return_break(widget, event): return 'break' self._id = widget.bind('') widget.bind('', _return_break) which should remove the motion-selection binding and then restore it after the dnd operation has finished by adding self.initial_widget.bind('', self._id) to the end of DnDHandler.finish() (untested however). Regards Michael .-.. .. ...- . .-.. --- -. --. .- -. -.. .--. .-. --- ... .--. . .-. "The combination of a number of things to make existence worthwhile." "Yes, the philosophy of 'none,' meaning 'all.'" -- Spock and Lincoln, "The Savage Curtain", stardate 5906.4 _______________________________________________ Tkinter-discuss mailing list Tkinter-discuss at python.org https://mail.python.org/mailman/listinfo/tkinter-discuss