wxPython中的拖放
在计算机图形用户界面中,拖放是指点击一个虚拟对象并将其拖到不同的位置或另一个虚拟对象上的动作(或支持该动作)。一般来说,它可以用来调用多种操作,或者在两个抽象对象之间创建各种类型的关联。
拖放操作可以让你直观地完成复杂的事情。
在拖放操作中,我们将一些数据从数据源拖到数据目标上。所以我们必须要有
- 一些数据
- 一个数据源
- 一个数据目标
在wxPython中,我们有两个预定义的数据目标。wx.TextDropTarget
和wx.FileDropTarget
。
wx.TextDropTarget
wx.TextDropTarget
是一个预定义的用于处理文本数据的投放目标。
#dragdrop_text.py
from pathlib import Path
import os
import wx
class MyTextDropTarget(wx.TextDropTarget):
def __init__(self, object):
wx.TextDropTarget.__init__(self)
self.object = object
def OnDropText(self, x, y, data):
self.object.InsertItem(0, data)
return True
class Example(wx.Frame):
def __init__(self, *args, **kw):
super(Example, self).__init__(*args, **kw)
self.InitUI()
def InitUI(self):
splitter1 = wx.SplitterWindow(self, style=wx.SP_3D)
splitter2 = wx.SplitterWindow(splitter1, style=wx.SP_3D)
home_dir = str(Path.home())
self.dirWid = wx.GenericDirCtrl(splitter1, dir=home_dir,
style=wx.DIRCTRL_DIR_ONLY)
self.lc1 = wx.ListCtrl(splitter2, style=wx.LC_LIST)
self.lc2 = wx.ListCtrl(splitter2, style=wx.LC_LIST)
dt = MyTextDropTarget(self.lc2)
self.lc2.SetDropTarget(dt)
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.lc1.GetId())
tree = self.dirWid.GetTreeCtrl()
splitter2.SplitHorizontally(self.lc1, self.lc2, 150)
splitter1.SplitVertically(self.dirWid, splitter2, 200)
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelect, id=tree.GetId())
self.OnSelect(0)
self.SetTitle('Drag and drop text')
self.Centre()
def OnSelect(self, event):
list = os.listdir(self.dirWid.GetPath())
self.lc1.ClearAll()
self.lc2.ClearAll()
for i in range(len(list)):
if list[i][0] != '.':
self.lc1.InsertItem(0, list[i])
def OnDragInit(self, event):
text = self.lc1.GetItemText(event.GetIndex())
tdo = wx.TextDataObject(text)
tds = wx.DropSource(self.lc1)
tds.SetData(tdo)
tds.DoDragDrop(True)
def main():
app = wx.App()
ex = Example(None)
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
![image-20201031161853768](https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201031161853768.png)
在本例中,我们在wx.GenericDirCtrl
中显示了一个文件系统。所选目录的内容显示在右上角的列表控件中,文件名可以拖放到右下角的列表控件中。
def OnDropText(self, x, y, data):
self.object.InsertItem(0, data)
return True
当我们将文本数据投放到目标上时,通过InsertItem()方法将数据插入到列表控件中。
dt = MyTextDropTarget(self.lc2)
self.lc2.SetDropTarget(dt)
一个下拉目标被创建。我们使用SetDropTarget()方法将投放目标设置为第二个列表控件。
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.lc1.GetId())
当拖动操作开始时,会调用OnDragInit()方法。
def OnDragInit(self, event):
text = self.lc1.GetItemText(event.GetIndex())
tdo = wx.TextDataObject(text)
tds = wx.DropSource(self.lc1)
...
在OnDragInit()
方法中,我们创建一个wx.TextDataObject
,其中包含我们的文本数据。从第一个列表控件中创建一个投放源。
tds.SetData(tdo)
tds.DoDragDrop(True)
我们用SetData()为投放源设置数据,用DoDragDrop()启动拖放操作。
wx.FileDropTarget
wx.FileDropTarget
是一个可以接受从文件管理器中拖动的文件的投放目标。
#dragdrop_file.py
import wx
class FileDrop(wx.FileDropTarget):
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.window = window
def OnDropFiles(self, x, y, filenames):
for name in filenames:
try:
file = open(name, 'r')
text = file.read()
self.window.WriteText(text)
except IOError as error:
msg = "Error opening file\n {}".format(str(error))
dlg = wx.MessageDialog(None, msg)
dlg.ShowModal()
return False
except UnicodeDecodeError as error:
msg = "Cannot open non ascii files\n {}".format(str(error))
dlg = wx.MessageDialog(None, msg)
dlg.ShowModal()
return False
finally:
file.close()
return True
class Example(wx.Frame):
def __init__(self, *args, **kw):
super(Example, self).__init__(*args, **kw)
self.InitUI()
def InitUI(self):
self.text = wx.TextCtrl(self, style = wx.TE_MULTILINE)
dt = FileDrop(self.text)
self.text.SetDropTarget(dt)
self.SetTitle('File drag and drop')
self.Centre()
def main():
app = wx.App()
ex = Example(None)
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
![image-20201031162055685](https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201031162055685.png)
这个例子创建了一个简单的wx.TextCtrl。我们可以从文件管理器中拖动文本文件到控件中。
def OnDropFiles(self, x, y, filenames):
for name in filenames:
...
我们可以一次拖放多个文件。
try:
file = open(name, 'r')
text = file.read()
self.window.WriteText(text)
我们以只读模式打开文件,获取其内容并将内容写入文本控制窗口。
except IOError as error:
msg = "Error opening file\n {}".format(str(error))
dlg = wx.MessageDialog(None, msg)
dlg.ShowModal()
return False
如果出现输入/输出错误,我们将显示一个消息对话框并终止操作。
self.text = wx.TextCtrl(self, style = wx.TE_MULTILINE)
dt = FileDrop(self.text)
self.text.SetDropTarget(dt)
wx.TextCtrl是拖放目标。