With the "SetClipboardViewer" function you can add a window to the chain of clipboard viewers. Whenever the content of the clipboard changes, a message is send to the clipboard viewer windows. A clipboard viewer window must process two messages and pass them to the next window in the chain. With a sample about hooking the window procedure of a wxPython Frame, I made up the following clipboard viewer.
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 | import wx
import win32api
import win32gui
import win32con
import win32clipboard
class TestFrame (wx.Frame):
def __init__ (self):
wx.Frame.__init__ (self, None, title="Clipboard viewer", size=(250,150))
self.first = True
self.nextWnd = None
# Get native window handle of this wxWidget Frame.
self.hwnd = self.GetHandle ()
# Set the WndProc to our function.
self.oldWndProc = win32gui.SetWindowLong (self.hwnd,
win32con.GWL_WNDPROC,
self.MyWndProc)
try:
self.nextWnd = win32clipboard.SetClipboardViewer (self.hwnd)
except win32api.error:
if win32api.GetLastError () == 0:
# information that there is no other window in chain
pass
else:
raise
def MyWndProc (self, hWnd, msg, wParam, lParam):
if msg == win32con.WM_CHANGECBCHAIN:
self.OnChangeCBChain (msg, wParam, lParam)
elif msg == win32con.WM_DRAWCLIPBOARD:
self.OnDrawClipboard (msg, wParam, lParam)
# Restore the old WndProc. Notice the use of win32api
# instead of win32gui here. This is to avoid an error due to
# not passing a callable object.
if msg == win32con.WM_DESTROY:
if self.nextWnd:
win32clipboard.ChangeClipboardChain (self.hwnd, self.nextWnd)
else:
win32clipboard.ChangeClipboardChain (self.hwnd, 0)
win32api.SetWindowLong (self.hwnd,
win32con.GWL_WNDPROC,
self.oldWndProc)
# Pass all messages (in this case, yours may be different) on
# to the original WndProc
return win32gui.CallWindowProc (self.oldWndProc,
hWnd, msg, wParam, lParam)
def OnChangeCBChain (self, msg, wParam, lParam):
if self.nextWnd == wParam:
# repair the chain
self.nextWnd = lParam
if self.nextWnd:
# pass the message to the next window in chain
win32api.SendMessage (self.nextWnd, msg, wParam, lParam)
def OnDrawClipboard (self, msg, wParam, lParam):
if self.first:
self.first = False
else:
print "clipboard content changed"
if self.nextWnd:
# pass the message to the next window in chain
win32api.SendMessage (self.nextWnd, msg, wParam, lParam)
app = wx.PySimpleApp ()
frame = TestFrame ()
frame.Show ()
app.MainLoop ()
|
Warning When you abort this script with Ctrl-C etc. the frame not receives the WM_DESTROY message and the clipboard chain could be left damaged.
Task You get informed whenever the clipboard content changes without the need to poll . I use this in an wxPython/Pyro application to sync the clipboard of computers over the network.
Alternatives I think you can not do this with wx.TheClipboard () because it is a platform dependent feature. You can do this without wxPython using functions like "win32gui.CreateWindow". There is already a 95 % working example on the net. Google for "win32clipboard.SetClipboardViewer"! Unfortunately, I don't know if there is a way to do this on linux.
Add a view to the viewer. Why not add a little view to the viewer? ;)
In __init__ add:
Now add the method:
Subsequently, change your OnDrawClipboard method to something like: