forked from pmgagne/tkinterdnd2
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathdemo_files_and_text.py
executable file
·173 lines (151 loc) · 6.46 KB
/
demo_files_and_text.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# -*- coding: utf-8 -*-
import os
import platform
from tkinterdnd2 import *
try:
from Tkinter import *
from ScrolledText import ScrolledText
except ImportError:
from tkinter import *
from tkinter.scrolledtext import ScrolledText
root = TkinterDnD.Tk()
root.withdraw()
root.title('TkinterDnD demo')
root.grid_rowconfigure(1, weight=1, minsize=250)
root.grid_columnconfigure(0, weight=1, minsize=300)
root.grid_columnconfigure(1, weight=1, minsize=300)
def print_event_info(event):
print('\nAction:', event.action)
print('Supported actions:', event.actions)
print('Mouse button:', event.button)
print('Type codes:', event.codes)
print('Current type code:', event.code)
print('Common source types:', event.commonsourcetypes)
print('Common target types:', event.commontargettypes)
print('Data:', event.data)
print('Event name:', event.name)
print('Supported types:', event.types)
print('Modifier keys:', event.modifiers)
print('Supported source types:', event.supportedsourcetypes)
print('Operation type:', event.type)
print('Source types:', event.sourcetypes)
print('Supported target types:', event.supportedtargettypes)
print('Widget:', event.widget, '(type: %s)' % type(event.widget))
print('X:', event.x_root)
print('Y:', event.y_root, '\n')
Label(root, text='Drag and drop files here:').grid(
row=0, column=0, padx=10, pady=5)
Label(root, text='Drag and drop text here:').grid(
row=0, column=1, padx=10, pady=5)
buttonbox = Frame(root)
buttonbox.grid(row=2, column=0, columnspan=2, pady=5)
Button(buttonbox, text='Quit', command=root.quit).pack(
side=LEFT, padx=5)
##############################################################################
###### Basic demo window: a Listbox to drag & drop files ##
###### and a Text widget to drag & drop text ##
##############################################################################
listbox = Listbox(root, name='dnd_demo_listbox',
selectmode='extended', width=1, height=1)
listbox.grid(row=1, column=0, padx=5, pady=5, sticky='news')
text = Text(root, name='dnd_demo_text', wrap='word', undo=True, width=1, height=1)
text.grid(row=1, column=1, pady=5, sticky='news')
listbox.insert(END, os.path.abspath(__file__))
info = 'TkinterDnD demo\nDetected versions:\n'
info += ' Python: %s\n' % platform.python_version()
info += ' Tk : %f\n' % TkVersion
info += ' Tkdnd : %s\n' % TkinterDnD.TkdndVersion
info += 'Use mouse button 3 to drag hightlighted text from the text box.\n'
text.insert(END, info)
# Drop callbacks can be shared between the Listbox and Text;
# according to the man page these callbacks must return an action type,
# however they also seem to work without
def drop_enter(event):
event.widget.focus_force()
print('Entering widget: %s' % event.widget)
#print_event_info(event)
return event.action
def drop_position(event):
print('Position: x %d, y %d' %(event.x_root, event.y_root))
#print_event_info(event)
return event.action
def drop_leave(event):
print('Leaving %s' % event.widget)
#print_event_info(event)
return event.action
def drop(event):
if event.data:
print('Dropped data:\n', event.data)
#print_event_info(event)
if event.widget == listbox:
# event.data is a list of filenames as one string;
# if one of these filenames contains whitespace characters
# it is rather difficult to reliably tell where one filename
# ends and the next begins; the best bet appears to be
# to count on tkdnd's and tkinter's internal magic to handle
# such cases correctly; the following seems to work well
# at least with Windows and Gtk/X11
files = listbox.tk.splitlist(event.data)
for f in files:
if os.path.exists(f):
print('Dropped file: "%s"' % f)
listbox.insert('end', f)
else:
print('Not dropping file "%s": file does not exist.' % f)
elif event.widget == text:
# calculate the mouse pointer's text index
bd = text['bd'] + text['highlightthickness']
x = event.x_root - text.winfo_rootx() - bd
y = event.y_root - text.winfo_rooty() - bd
index = text.index('@%d,%d' % (x,y))
text.insert(index, event.data)
else:
print('Error: reported event.widget not known')
return event.action
# now make the Listbox and Text drop targets
listbox.drop_target_register(DND_FILES, DND_TEXT)
text.drop_target_register(DND_TEXT)
for widget in (listbox, text):
widget.dnd_bind('<<DropEnter>>', drop_enter)
widget.dnd_bind('<<DropPosition>>', drop_position)
widget.dnd_bind('<<DropLeave>>', drop_leave)
widget.dnd_bind('<<Drop>>', drop)
#widget.dnd_bind('<<Drop:DND_Files>>', drop)
#widget.dnd_bind('<<Drop:DND_Text>>', drop)
# define drag callbacks
def drag_init_listbox(event):
print_event_info(event)
# use a tuple as file list, this should hopefully be handled gracefully
# by tkdnd and the drop targets like file managers or text editors
data = ()
if listbox.curselection():
data = tuple([listbox.get(i) for i in listbox.curselection()])
print('Dragging :', data)
# tuples can also be used to specify possible alternatives for
# action type and DnD type:
return ((ASK, COPY), (DND_FILES, DND_TEXT), data)
def drag_init_text(event):
print_event_info(event)
# use a string if there is only a single text string to be dragged
data = ''
sel = text.tag_nextrange(SEL, '1.0')
if sel:
data = text.get(*sel)
print('Dragging :\n', data)
# if there is only one possible alternative for action and DnD type
# we can also use strings here
return (COPY, DND_TEXT, data)
def drag_end(event):
#print_event_info(event)
# this callback is not really necessary if it doesn't do anything useful
print('Drag ended for widget:', event.widget)
# finally make the widgets a drag source
listbox.drag_source_register(1, DND_TEXT, DND_FILES)
text.drag_source_register(3, DND_TEXT)
listbox.dnd_bind('<<DragInitCmd>>', drag_init_listbox)
listbox.dnd_bind('<<DragEndCmd>>', drag_end)
text.dnd_bind('<<DragInitCmd>>', drag_init_text)
# skip the useless drag_end() binding for the text widget
root.update_idletasks()
root.deiconify()
root.mainloop()