wxWidgets可以很方便的处理Windows消息,只要重载wxWindow类中的MSWWindowProc函数就可以了。而wxPython是没提供这个方法的,需要用pywin32模块调用几个Win32 API才能实现处理Windows消息。虽然麻烦了点,但总比没有解决办法要好。
Sometimes you may need to catch a Windows message that is not already handled by wxWidgets, so there is no wxEvent for it. With a bit of help from the PyWin32 modules it is possible to hook into the WndProc chain for a wxWindow and watch for the message you are interested in.
The magic is in the win32gui.SetWindowLong function. When used with the win32con.GWL_WNDPROC flag it causes a new WndProc to be set for the window, and returns the old one. This lets you write a function in Python that can get first crack at all the Windows messages being sent to the window, and if you are not interested in them then pass them on to the original wxWidgets WndProc.
方法一:
import wx
import win32api
import win32gui
import win32con
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="WndProc Test", size=(200,150))
p = wx.Panel(self)
# Set the WndProc to our function
self.oldWndProc = win32gui.SetWindowLong(self.GetHandle(),
win32con.GWL_WNDPROC,
self.MyWndProc)
# Make a dictionary of message names to be used for printing below
self.msgdict = {}
for name in dir(win32con):
if name.startswith("WM_"):
value = getattr(win32con, name)
self.msgdict[value] = name
def MyWndProc(self, hWnd, msg, wParam, lParam):
# Display what we've got.
print (self.msgdict.get(msg), msg, wParam, lParam)
# Restore the old WndProc. Notice the use of wxin32api
# instead of win32gui here. This is to avoid an error due to
# not passing a callable object.
if msg == win32con.WM_DESTROY:
win32api.SetWindowLong(self.GetHandle(),
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)
app = wx.PySimpleApp()
f = TestFrame()
f.Show()
app.MainLoop()
import wx
import win32api
import win32gui
import win32con
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="WndProc Test", size=(200,150))
p = wx.Panel(self)
# Set the WndProc to our function
self.oldWndProc = win32gui.SetWindowLong(self.GetHandle(),
win32con.GWL_WNDPROC,
self.MyWndProc)
# Make a dictionary of message names to be used for printing below
self.msgdict = {}
for name in dir(win32con):
if name.startswith("WM_"):
value = getattr(win32con, name)
self.msgdict[value] = name
def MyWndProc(self, hWnd, msg, wParam, lParam):
# Display what we've got.
print (self.msgdict.get(msg), msg, wParam, lParam)
# Restore the old WndProc. Notice the use of wxin32api
# instead of win32gui here. This is to avoid an error due to
# not passing a callable object.
if msg == win32con.WM_DESTROY:
win32api.SetWindowLong(self.GetHandle(),
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)
app = wx.PySimpleApp()
f = TestFrame()
f.Show()
app.MainLoop()
方法二:
import ctypes
import wx
from ctypes import c_long, c_int
# grab the functions we need - unicode/not doesn't really matter
# for this demo
SetWindowLong = ctypes.windll.user32.SetWindowLongW
CallWindowProc = ctypes.windll.user32.CallWindowProcW
# a function type for the wndprc so ctypes can wrap it
WndProcType = ctypes.WINFUNCTYPE(c_int, c_long, c_int, c_int, c_int)
# constants
GWL_WNDPROC = -4
class TestFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
# need to hold a reference to WINFUNCTYPE wrappers,
# so they don't get GCed
self.newWndProc = WndProcType(self.MyWndProc)
self.oldWndProc = SetWindowLong(
self.GetHandle(),
GWL_WNDPROC,
self.newWndProc
)
def MyWndProc(self, hWnd, msg, wParam, lParam):
print msg,wParam,lParam
return CallWindowProc(
self.oldWndProc,
hWnd,
msg,
wParam,
lParam
)
app =wx.App(False)
f = TestFrame(None)
f.Show()
app.MainLoop()