import os, traceback from ctypes import * from ctypes.wintypes import * gdiplus = windll.gdiplus SW_HIDE = 0 SW_SHOW = 5 GWL_WNDPROC = -4 GWL_STYLE = -16 CS_VREDRAW = 0x0001 CS_HREDRAW = 0x0002 CS_GLOBALCLASS = 0x4000 WS_OVERLAPPEDWINDOW = 13565952 WS_VISIBLE = 0x10000000 WS_SYSMENU = 0x00080000 WM_QUIT = 0x0012 WM_PAINT = 0x000f WM_CLOSE = 0x0010 LF_FACESIZE = 32 WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int) 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_char_p), ('lpszClassName', c_char_p), ] class PAINTSTRUCT(Structure): _fields_ = [ ('hdc', c_int), ('fErase', c_int), ('rcPaint', RECT), ('fRestore', c_int), ('fIncUpdate', c_int), ('rgbReserved', c_char * 32), ] lo_byte = lambda x : x & 0xff hi_byte = lambda x : x >> 8 & 0xff lo_word = lambda x : x & 0xffff hi_word = lambda x : x >> 16 & 0xffff class RectF(Structure): _fields_ = [ ('x', c_float), ('y', c_float), ('w', c_float), ('h',c_float), ] class LOGFONT(Structure): _fields_ = [ ('lfHeight', c_long), ('lfWidth', c_long), ('lfEscapement', c_long), ('lfOrientation', c_long), ('lfWeight', c_long), ('lfItalic', c_byte), ('lfUnderline', c_byte), ('lfStrikeOut', c_byte), ('lfCharSet', c_byte), ('lfOutPrecision', c_byte), ('lfClipPrecision', c_byte), ('lfQuality', c_byte), ('lfPitchAndFamily', c_byte), ('lfFaceName', c_char * LF_FACESIZE), ] def __init__(self): self.lfHeight, self.lfWidth = 10, 10 self.lfEscapement = 10 self.lfOrientation = 0 self.lfUnderline = 0 self.lfStrikeOut = 0 self.lfCharSet = 0 # ANSI_CHARSET self.lfPitchAndFamily = 0 self.lfOutPrecision = 0 self.lfClipPrecision = 0 self.lfQuality = 0 self.lfPitchAndFamily = 2 class GdiplusStartupInput(Structure): _fields_ = [ ('GdiplusVersion', c_uint), ('DebugEventCallback', c_void_p), ('SuppressBackgroundThread', BOOL), ('SuppressExternalCodecs', BOOL), ] def __init__(self): Structure.__init__(self) self.GdiplusVersion = 1 self.DebugEventCallback = None self.SuppressBackgroundThread = 0 self.SuppressExternalCodecs = 0 StartupInput = GdiplusStartupInput() token = c_ulong() gdiplus.GdiplusStartup(pointer(token), pointer(StartupInput), None) class Font(object): def __init__(self, family, size = 12, style = []): logfont = LOGFONT() logfont.lfFaceName = family logfont.lfHeight = -size logfont.lfWidth = 0 if 'italic' in style: logfont.lfItalic = 1 else: logfont.lfItalic = 0 if 'bold' in style: logfont.lfWeight = 10 else: logfont.lfWeight = 0 self._size = size self._win32_object = windll.gdi32.CreateFontIndirectA(byref(logfont)) self._free_object = True self._family = family # should came elsewhere class Canvas(object): def __init__(self, hdc): self._hdc = hdc self._GpGraphics = c_void_p() gdiplus.GdipCreateFromHDC(hdc, byref(self._GpGraphics)) self._GpFont = c_void_p() self._GpBrush = c_void_p() gdiplus.GdipCreateSolidFill(0xff000000, byref(self._GpBrush)) print "Canvas: brush =", self._GpBrush.value ### self._GpPen = c_void_p() gdiplus.GdipCreatePen1(0xff000000, c_float(1.0), 2, byref(self._GpPen)) def set_font(self, f): windll.gdi32.SelectObject(self._hdc, f._win32_object) gdiplus.GdipDeleteFont(self._GpFont) gdiplus.GdipCreateFontFromDC(self._hdc, byref(self._GpFont)) self._font = f def show_text(self, x, y, text): font = self._font _rect = RectF(x, y, 0, 0) size = len(text) gdiplus.GdipDrawString(self._GpGraphics, unicode(text), size, self._GpFont, byref(_rect), None, self._GpBrush) def set_forecolor(self, color): gdiplus.GdipSetSolidFillColor(self._GpBrush, c_int(color)) gdiplus.GdipSetPenColor(self._GpPen, c_int(color)) def fill_rect(self, rect): print "fill_rect", rect, "with", self._GpBrush.value ### l, t, r, b = rect gdiplus.GdipFillRectangle(self._GpGraphics, self._GpBrush, c_float(l), c_float(t), c_float(r - l), c_float(b - t)) class Test(object): def __init__(self): self.cname = "FOO" wcls = WNDCLASS() wcls.style = 0 #CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW wcls.lpfnWndProc = WNDPROC(window_proc) wcls.cbClsExtra = wcls.cbWndExtra = 0 wcls.hInstance = windll.kernel32.GetModuleHandleA(c_int(0)) wcls.hbrBackground = 0 #wc.COLOR_WINDOW + 1 wcls.lpszMenuName = None wcls.lpszClassName = self.cname self.wcls = wcls windll.user32.RegisterClassA(byref(wcls)) hwnd = windll.user32.CreateWindowExA( 0, # styleEx "FOO", # className "Test GDI+ Text - ctypes", # windowTitle WS_OVERLAPPEDWINDOW | WS_VISIBLE, # style 100, 100, 400, 100, # x, y, width, height, 0, # parent 0, # menu 0, # hinstance 0 # reserved ) self.hwnd = hwnd # def OnClose(self): # gui.PostQuitMessage(0) def OnPaint(self): print "OnPaint" hwnd = self.hwnd ps = PAINTSTRUCT() hdc = windll.user32.BeginPaint(hwnd, byref(ps)) yellow = 0xffffff00 black = 0xff000000 canvas = Canvas(hdc) canvas.set_forecolor(yellow) canvas.fill_rect((0, 0, 400, 100)) canvas.set_forecolor(black) font = Font("Times", 48, []) canvas.set_font(font) canvas.show_text(0, 0, "Times Italic 48") windll.user32.EndPaint(hwnd, byref(ps)) def window_proc(hwnd, msg, lparam, wparam): try: print "window_proc:", hwnd, msg, lparam, wparam ### if msg == WM_CLOSE: os._exit(0) elif msg == WM_PAINT: test.OnPaint() return 1 return windll.user32.DefWindowProcA(hwnd, msg, lparam, wparam) except: traceback.print_exc() os._exit(1) test = Test() msg = MSG() while 1: windll.user32.GetMessageA(byref(msg), 0, 0, 0) windll.user32.TranslateMessage(byref(msg)) windll.user32.DispatchMessageA(byref(msg))