我正在尝试创建一个可以显示图形的窗口,但在消息循环中我收到“WindowsError:异常:访问冲突写入 0xC0000000”错误。据我从这里提出的其他问题中了解到,这是由于尝试写入错误位置的方法。
该代码是对此处找到的内容的改编,但消息循环功能保持不变;我什至尝试过使用 PeekMessage 和其他各种方法。
from ctypes import *
import win32con
_WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int)
_NULL = c_int(win32con.NULL)
_user32 = windll.user32
_gdi32 = windll.gdi32
def _ErrorIfZero(handle):
if handle == 0:
raise WinError()
else:
return handle
CreateWindowEx = _user32.CreateWindowExW
CreateWindowEx.argtypes = [c_int,
c_wchar_p,
c_wchar_p,
c_int,
c_int,
c_int,
c_int,
c_int,
c_int,
c_int,
c_int,
c_int]
CreateWindowEx.restype = _ErrorIfZero
class _WNDCLASS(Structure):
_fields_ = [('style', c_uint),
('lpfnWndProc', _WNDPROC),
('cbClsExtra', c_int),
('cbWndExtra', c_int),
('hInstance', c_int),
('hIcon', c_int),
('hCursor', c_int),
('hbrBackground', c_int),
('lpszMenuName', c_wchar_p),
('lpszClassName', c_wchar_p)]
def __init__(self,
wndProc,
style=win32con.CS_HREDRAW | win32con.CS_VREDRAW,
clsExtra=0,
wndExtra=0,
menuName=None,
className=u"PythonWin32",
instance=None,
icon=None,
cursor=None,
background=None,
):
if not instance:
instance = windll.kernel32.GetModuleHandleW(c_int(win32con.NULL))
if not icon:
icon = _user32.LoadIconW(c_int(win32con.NULL),
c_int(win32con.IDI_APPLICATION))
if not cursor:
cursor = _user32.LoadCursorW(c_int(win32con.NULL),
c_int(win32con.IDC_ARROW))
if not background:
background = windll.gdi32.GetStockObject(c_int(win32con.WHITE_BRUSH))
self.lpfnWndProc=wndProc
self.style=style
self.cbClsExtra=clsExtra
self.cbWndExtra=wndExtra
self.hInstance=instance
self.hIcon=icon
self.hCursor=cursor
self.hbrBackground=background
self.lpszMenuName=menuName
self.lpszClassName=className
class _RECT(Structure):
_fields_ = [('left', c_long),
('top', c_long),
('right', c_long),
('bottom', c_long)]
def __init__(self, left=0, top=0, right=0, bottom=0 ):
self.left = left
self.top = top
self.right = right
self.bottom = bottom
class _PAINTSTRUCT(Structure):
_fields_ = [('hdc', c_int),
('fErase', c_int),
('rcPaint', _RECT),
('fRestore', c_int),
('fIncUpdate', c_int),
('rgbReserved', c_wchar * 32)]
class _POINT(Structure):
_fields_ = [('x', c_long),
('y', c_long)]
def __init__( self, x=0, y=0 ):
self.x = x
self.y = y
class _MSG(Structure):
_fields_ = [('hwnd', c_int),
('message', c_uint),
('wParam', c_int),
('lParam', c_int),
('time', c_int),
('pt', _POINT)]
def RunMessageLoop():
"""Runs the loop to get messages from"""
msg = _MSG()
pMsg = pointer(msg)
while _user32.GetMessageW(pMsg, _NULL, 0, 0):
_user32.TranslateMessage(pMsg)
_user32.DispatchMessageW(pMsg)
return msg.wParam
## Lifted shamelessly from WCK (effbot)'s wckTkinter.bind
def EventHandler(message):
"""Decorator for event handlers"""
def decorator(func):
func.win32message = message
return func
return decorator
class Window(object):
"""The application window"""
def __init__(self, title, updateHandler):
#Store update function
self.updateHandler = updateHandler
#Register event handlers
self._event_handlers = {}
for key in dir(self):
method = getattr(self, key)
if hasattr(method, "win32message") and callable(method):
self._event_handlers[method.win32message] = method
#Register window class
wndclass = _WNDCLASS(_WNDPROC(self.WndProc))
wndclass.lpszClassName = u"HelloWindow"
if not _user32.RegisterClassW(byref(wndclass)):
raise WinError()
#Now create the _Window
self.Create( className=wndclass.lpszClassName,
instance=wndclass.hInstance,
windowName=title)
#Show Window
self.Show(win32con.SW_SHOWNORMAL)
self.Update()
def GetSize(self):
rect = _RECT()
_user32.GetClientRect(self.hwnd, byref(rect))
return rect.width, rect.height
def Create(self,
exStyle=0 , # DWORD dwExStyle
className=u"WndClass",
windowName=u"Window",
style=win32con.WS_OVERLAPPEDWINDOW,
x=win32con.CW_USEDEFAULT,
y=win32con.CW_USEDEFAULT,
width=win32con.CW_USEDEFAULT,
height=win32con.CW_USEDEFAULT,
parent=_NULL,
menu=_NULL,
instance=_NULL,
lparam=_NULL,
):
self.hwnd = CreateWindowEx(exStyle,
className,
windowName,
style,
x,
y,
width,
height,
parent,
menu,
instance,
lparam)
return self.hwnd
def Show(self, flag):
return _user32.ShowWindow(self.hwnd, flag)
def Update(self):
if not _user32.UpdateWindow(self.hwnd):
raise WinError()
def WndProc(self, hwnd, message, wParam, lParam):
event_handler = self._event_handlers.get(message, None)
if event_handler:
return event_handler(message, wParam, lParam)
return _user32.DefWindowProcW(c_int(hwnd),
c_int(message),
c_int(wParam),
c_int(lParam))
"""Yipee Events :'( """
@EventHandler(win32con.WM_PAINT)
def OnPaint(self, message, wParam, lParam):
"""Window is updating so update graphics inside"""
ps = _PAINTSTRUCT()
hdc = _user32.BeginPaint(c_int(self.hwnd), byref(ps))
self.updateHandler(hdc)
_user32.EndPaint(c_int(self.hwnd), byref(ps))
return 0
@EventHandler(win32con.WM_DESTROY)
def OnDestroy(self, message, wParam, lParam):
"""Quit app when window is destroyed"""
_user32.PostQuitMessage(0)
return 0
class DrawMethods:
@staticmethod
def DrawLine(handle, x1, y1, x2, y2):
"""Draw a line between points"""
_gdi32.MoveToEx(c_int(handle),
x1,
y1,
NULL)
_gdi32.LineTo(c_int(hdc),
x2,
y2)
@staticmethod
def DrawRect(handle, x, y, width, height):
"""Draw a rect at x and y of width and height"""
_gdi32.Rectangle(c_int(handle),
x,
y,
x+width,
y+height)
#@staticmethod
#def DrawCircle(x, y, radius):
@staticmethod
def DrawText(handle, x, y, width, height, text):
"""Draw text at the specified coordinates""" # UPDATE!!!!
rect = _RECT(x, y, width, height)
flags = win32con.DT_SINGLELINE|win32con.DT_CENTER|win32con.DT_VCENTER
_user32.DrawTextW(c_int(handle),
text,
c_int(-1),
byref(rect),
flags)
class Test:
"""Create window and start message loop"""
def __init__(self):
#So create a window (yes this is multi window compatible I think) titled "TestWindow!" that calls the Update method to draw everything
self.window = Window("Test Window!", self.Update)
def Update(self, handle):
"""This is called when the window updates and you can then use the drawing functions available in Renderer.DrawMethods"""
#Renderer omitted as in the same file
DrawMethods.DrawText( handle, 0, 0, 500, 500, u"Helllloooo!!! Testy testy test test :D" )
t= Test()
RunMessageLoop()
我希望有人可以帮助我,该代码设计用于在任何 Windows 机器上运行,因此您应该能够运行它(据说 win32con 导入可能是 pywin32 包的一部分......)
谢谢,
杰米 :)