应用剪贴板
剪贴板(Clipboard)是系统广泛应用的在应用之间获取数据的方式。这个部分将展示如何从剪贴版获得文本,同样如何把文本放到剪贴板上以供其他应用来使用。
How to do it?
译注:下面两个函数用来从剪贴板获取(GetClipboardText)和放入文本(SetClipboardText),点击"Copy"按钮便把第一个输入框(copyCtr)中文本放入剪贴板,点击“Paste”按钮便使第二个输入框(pastCtr)获取剪贴板的文本。在Windows系统中其余应用中复制到剪贴板的文本也可以粘贴到第二个输入框,第一个输入框的内容也可以粘贴到其他程序中。
import wx
class ClipboardFrame(wx.Frame):
def __init__(self, parent, id = wx.ID_ANY, title = "",
pos = wx.DefaultPosition, size = wx.DefaultSize,
style = wx.DEFAULT_FRAME_STYLE, name = "ClipboardFrame"):
super(ClipboardFrame, self).__init__(parent, id, title,
pos, size, style, name)
panel = wx.Panel(self)
copyBt = wx.Button(panel, label = "Copy")
pastBt = wx.Button(panel, label = "Paste")
self.copyCtr = wx.TextCtrl(panel)
self.pastCtr = wx.TextCtrl(panel)
copyBt.Bind(wx.EVT_BUTTON, self.OnCopy)
pastBt.Bind(wx.EVT_BUTTON, self.OnPast)
box1 = wx.BoxSizer(wx.HORIZONTAL)
box1.Add(copyBt, 1, wx.EXPAND)
box1.Add(pastBt, 1, wx.EXPAND)
box2 = wx.BoxSizer(wx.HORIZONTAL)
box2.AddMany([self.copyCtr, self.pastCtr])
pbox = wx.BoxSizer(wx.VERTICAL)
pbox.Add(box1, 1, wx.EXPAND)
pbox.Add(box2, 1, wx.EXPAND)
panel.SetSizer(pbox)
pbox.Fit(self)
fbox = wx.BoxSizer(wx.VERTICAL)
fbox.Add(panel)
self.SetSizer(fbox)
def OnCopy(self, event):
print "OnCopy Trigger!\n"
self.SetClipboardText(self.copyCtr.GetValue())
def OnPast(self, event):
print "OnPast Trigger!\n"
self.pastCtr.SetValue(self.GetClipboardText())
def SetClipboardText(self,text):
"""Put text in the clipboard
@param text: string
"""
data_o = wx.TextDataObject()
data_o.SetText(text)
if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
wx.TheClipboard.SetData(data_o)
wx.TheClipboard.Close()
def GetClipboardText(self):
"""Get text from the clipboard
@return: string
"""
text_obj = wx.TextDataObject()
rtext = ""
if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
if wx.TheClipboard.GetData(text_obj):
rtext = text_obj.GetText()
wx.TheClipboard.Close()
return rtext
if __name__ == "__main__":
app = wx.PySimpleApp(False)
ClipboardFrame(None).Show()
app.MainLoop()
How it works?
wxPython提供一个单例(singleton)剪贴板对象来与系统的剪贴板交互。这个类针对代表系统底层数据类型的数据对象(data object)来工作。使用剪贴板包括下面三个步骤:
- 打开一个剪贴板
- 设置(Set)或获取(Get)数据对象
- 关闭剪贴板
There's more
剪贴板除了文本外还支持很多其他类型的数据类型。wxPython为你自己定义的数据类型也提供了内置(built-in)支持。下面各种不同数据类型的应用模式跟文本数据(TextDataObject)类似。
- wx.BitmapDataObject:Bitmap类型
- wx.CustomDataObject:任意Python序列化对象
- wx.DataObjectComposite:Can contain any arbitrary number of simple data types and make them all available at once
- wx.FileDataObject:文件名称
- wx.URLDataObject:URL地址
支持拖放(Drag and Drop)
为了提升可用性,在应用中最好能支持拖放操作,这样便于用户通过简单的拖放文件或其它对象来操作你的应用。这个部分将向你展示如何支持一个CompositeDataOjbect,其支持文件和文本。
How to do it?
import wx
class FileAndTextDropTarget(wx.PyDropTarget):
"""Drop target capable of accepting dropped
files and text"""
def __init__(self, file_callback, text_callback):
print "FileAndTextDropTarget Initializing!\n"
assert callable(file_callback)
assert callable(text_callback)
super(FileAndTextDropTarget, self).__init__()
# Attributes
self.fcallback = file_callback # Drop File Callback
self.tcallback = text_callback # Drop Text Callback
self._data = None
self.txtdo = None
self.filedo = None
# Setup
self.InitObjects()
def InitObjects(self):
"""Initializes the text and file data objects"""
print "InitObjects Trigger!\n"
self._data = wx.DataObjectComposite()
self.txtdo = wx.TextDataObject()
self.filedo = wx.FileDataObject()
self._data.Add(self.txtdo, False)
self._data.Add(self.filedo, True)
self.SetDataObject(self._data)
def OnData(self, x_cord, y_cord, drag_result):
"""Called by the framework when data is dropped
on the target
"""
print "OnData Trigger!\n"
if self.GetData():
data_format = self._data.GetReceivedFormat()
if data_format.GetType() == wx.DF_FILENAME:
self.fcallback(self.filedo.GetFilenames())
else:
self.tcallback(self.txtdo.GetText())
return drag_result
class DropTargetFrame(wx.Frame):
def __init__(self, parent, id = wx.ID_ANY, title = "",
pos = wx.DefaultPosition, size = wx.DefaultSize,
style = wx.DEFAULT_FRAME_STYLE, name = "DropTargetFrame"):
super(DropTargetFrame, self).__init__(parent, id, title,
pos, size, style, name)
choices = ["Drag and Drop Text or Files here", ]
self.list = wx.ListBox(self,
choices = choices)
self.dt = FileAndTextDropTarget(self.OnFileDrop,
self.OnTextDrop)
self.list.SetDropTarget(self.dt)
self.CreateStatusBar()
self.Fit()
def OnFileDrop(self, files):
print "OnFileDrop Trigger!\n"
self.PushStatusText("Files Dropped")
for f in files:
self.list.Append(f)
def OnTextDrop(self, text):
print "OnTextDrop Trigger!\n"
self.PushStatusText("Text Dropped")
self.list.Append(text)
if __name__ == "__main__":
app = wx.PySimpleApp(False)
DropTargetFrame(None).Show()
app.MainLoop()
How it works?
当窗口收到拖放的数据,框架(framework)将调用我们DropTarget中的OnData方法。在OnData方法中,我们简单从DataObject中获取数据并将它传递给合适的回调函数,由窗口来决定如何处理这些数据。所有的窗口对象都有SetDropTarget方法来用于设置一个DropTarget,所以这个类(
FileAndTextDropTarget
)可以在其他任何控件中复用。在上面的例子中,我们用列表框(ListBox)来展示拖放的数据。
译注:可以把“拖放”类理解为一个事件(event),这里需要我们继承 wx.PyDropTarget类,并设置支持的数据类型,本例子中就是文本(text)和文件(file)。在窗口(window)对象中的SetDropTarget相当于一个事件绑定,当有拖放事件时,便调用OnData回调方法进行处理。在例子中,OnData方法再根据拖放进入的不同数据类型,来调用窗口(window)中不同方法来处理。以拖放“hello world.txt”为例,其内容是“HELLO WORLD!”,发现windows下的记事本无法拖放文本,故需要在记事本下打开并选择文本拖放,下面两个图就是拖放的效果。
There's more
PyDropTarget类可以在拖拽的过程中提供许多其他的方法。这些方法可以被重现,这样便于实现变换鼠标图标,展示拖放图像,或拒绝拖放对象等操作。
- OnEnter(x, y, drag_result) 当拖放对象进入窗口时调用。返回一个拖放的结果值。
- OnDragOver(x, y, drag_result)当鼠标拖放一个对象在目标之上时调用。
- OnLeave() 当鼠标离开拖放对象时调用
- OnDrop(x, y)当用户释放对象时调用。返回True表示接受对象或者False表示拒绝
- OnData(x, y, drag_result) 当对象被接受后,在OnDrop后调用。