我正在制作一个应用程序,使用SDL/PYGAME显示图形.我已经重写了窗口过程,在调整大小以触发函数的情况下,使应用程序运行得更流畅(参见this answer).
然而,我注意到,当达到某个类的一定数量的实例时,它会在日志(log)中没有任何错误地使应用程序崩溃.我判断了Windows日志(log),但什么也找不到.我发现罪魁祸首是窗口程序覆盖.
下面是对该问题的模拟:
- 函数
windows_resize_procedure
(受this answer启发)在用户调整窗口大小时触发App.resize
和App.draw
-
[Element() for _ in range(1000)]
会人为地增加Element
个实例的数量.在我的实际程序中,我只有大约50个属性,但我认为它们"更大"(更多属性和方法).[Element() for _ in range(1000)]
0足以让我电脑上的程序在几秒钟内崩溃,但你可能想根据你的情况增加这个数字.
import pygame,sys,platform
def windows_resize_procedure(hwnd,draw_func,resize_func,screen):
try:
import ctypes
from ctypes import wintypes
user32 = ctypes.windll.user32
WNDPROC = ctypes.WINFUNCTYPE(
ctypes.c_long,
wintypes.HWND,
ctypes.c_uint,
ctypes.POINTER(wintypes.WPARAM),
ctypes.POINTER(wintypes.LPARAM))
WM_SIZE = 0x0005
RDW_INVALIDATE = 0x0001
RDW_ERASE = 0x0004
GWL_WNDPROC = -4
old_window_proc = user32.GetWindowLongPtrA(
user32.GetForegroundWindow(),
GWL_WNDPROC
)
def new_window_proc(hwnd, msg, wparam, lparam):
if msg == WM_SIZE:
resize_func(screen.get_size())
draw_func()
user32.RedrawWindow(hwnd, None, None, RDW_INVALIDATE | RDW_ERASE)
return user32.CallWindowProcA(old_window_proc, hwnd, msg, wparam, lparam)
new_window_proc_cb = WNDPROC(new_window_proc)
user32.SetWindowLongPtrA(
user32.GetForegroundWindow(),
GWL_WNDPROC,
ctypes.cast(new_window_proc_cb, ctypes.POINTER(ctypes.c_long))
)
except Exception as e:
print(e)
class Element:
def __init__(self):
self.foo = 'foo'
class App:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((200,200),pygame.RESIZABLE )
self.clock = pygame.time.Clock()
self.hwnd = pygame.display.get_wm_info()['window']
# Commenting the two following lines "fix" the issue
# Meaning when not overwritting the window procedure it works well
if platform.system() == 'Windows':
windows_resize_procedure(self.hwnd,self.draw,self.resize,self.screen)
self.elements = []
def inputs(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Simulating high volume of instances
[Element() for _ in range(1000)]
def resize(self,size):
print(f'resizing to {size}')
def draw(self):
self.screen.fill('white')
def run(self):
while True:
self.inputs()
pygame.display.update()
self.clock.tick()
if __name__ == "__main__":
app = App()
app.run()