#!python # -*- mode: python; Encoding: utf-8; coding: utf-8 -*- # Last updated: <2025/12/26 22:02:41 +0900> """ pywin32でウインドウを新規作成してウインドウハンドル(HWND)を取得。 そのHWNDに対して、背景色は黒、文字色は白で文字列を描画。 Google Gemini で生成。 Windows11 x64 25H2 + Python 3.10.10 64bit """ import win32gui import win32con import win32api FONT_NAME = "Meiryo" FONT_SIZE = 32 def on_paint(hwnd): """文字列をウインドウに描画""" # 描画開始 hdc, ps = win32gui.BeginPaint(hwnd) # クライアント領域のサイズを取得。(left, top, right, bottom) rect = win32gui.GetClientRect(hwnd) # 背景を黒で塗りつぶし hbrush = win32gui.CreateSolidBrush(win32api.RGB(0, 0, 0)) win32gui.FillRect(hdc, rect, hbrush) # 作成したGDIオブジェクトは削除していかないとメモリを圧迫(リソースリーク)する。 win32gui.DeleteObject(hbrush) # フォントの設定。LOGFONT構造体(辞書形式)で詳細を指定 lf = win32gui.LOGFONT() # フォント名、サイズ(高さ)、ウェイト、アンチエイリアスを設定 lf.lfFaceName = FONT_NAME lf.lfHeight = FONT_SIZE lf.lfWeight = win32con.FW_BOLD lf.lfQuality = win32con.ANTIALIASED_QUALITY # フォントオブジェクトの作成 hfont = win32gui.CreateFontIndirect(lf) # 作成したフォントオブジェクトをHDCに選択(戻り値は以前のフォント) hfont_old = win32gui.SelectObject(hdc, hfont) # 文字色指定 win32gui.SetTextColor(hdc, win32api.RGB(255, 255, 255)) win32gui.SetBkMode(hdc, win32con.TRANSPARENT) # 文字描画時の処理を指定、DT_WORDBREAK を指定すると改行も有効になる draw_style = win32con.DT_CENTER | win32con.DT_VCENTER | win32con.DT_WORDBREAK # 文字描画 lines = [ "Hello !", "Windows 11のフォント描画です。", f"Font : {FONT_NAME}", f"Size : {FONT_SIZE}", ] txt = "\n".join(lines) win32gui.DrawText(hdc, txt, -1, rect, draw_style) # 後片付け。元のフォントに戻して、作成したフォントを削除(メモリリーク防止) win32gui.SelectObject(hdc, hfont_old) win32gui.DeleteObject(hfont) # 描画終了 win32gui.EndPaint(hwnd, ps) def wnd_proc(hwnd, msg, wparam, lparam): """ウインドウプロシージャ。イベントメッセージ処理関数""" if msg == win32con.WM_PAINT: # 描画開始 on_paint(hwnd) return 0 if msg == win32con.WM_DESTROY: # ウィンドウ破棄時の処理(閉じるボタンが押された等) print("WM_DESTROY を受け取ったので Quit メッセージを送る。") win32gui.PostQuitMessage(0) return 0 # 自分で処理しないメッセージは、OS提供のデフォルト処理に任せる return win32gui.DefWindowProc(hwnd, msg, wparam, lparam) def create_window_with_custom_font(): """ウインドウを新規作成""" window_class_name = "PythonCustomFontWindow" # ウインドウクラスの登録 wc = win32gui.WNDCLASS() wc.lpszClassName = window_class_name wc.lpfnWndProc = wnd_proc wc.hInstance = win32api.GetModuleHandle(None) wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW) # 背景色を指定 wc.hbrBackground = win32gui.GetStockObject(win32con.BLACK_BRUSH) # wc.hbrBackground = win32gui.CreateSolidBrush(win32api.RGB(0, 0, 0)) # ウインドウリサイズ時に再描画するように指定 wc.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW # ウインドウクラスをOSに登録 try: win32gui.RegisterClass(wc) except win32gui.error as e: print(f"Error: {e}") if e.winerror != 1410: # 登録済みの場合は 1410 が返ってくるのでそれ以外はエラーとする # http://ir9.jp/prog/ayu/win32err.htm raise # ウインドウ新規作成。ウインドウハンドル(HWND)が返ってくる # CreateWindowEx() と CreateWindow() の違いは拡張スタイルを使えるかどうか hwnd = win32gui.CreateWindowEx( 0, # 拡張スタイル window_class_name, # 使用クラス名 "Font Selection Sample", # ウインドウタイトル win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE, # ウインドウスタイル win32con.CW_USEDEFAULT, # 表示位置 x (OSにまかせる) win32con.CW_USEDEFAULT, # 表示位置 y (OSにまかせる) 512, # ウインドウ幅 288, # ウインドウ高さ 0, # 親ウインドウ HWND 0, # メニューハンドル wc.hInstance, # インスタンス None, # 追加パラメータ ) if not hwnd: print("Error: ウインドウの作成に失敗") return None print(f"ウインドウを作成。 HWND: {hwnd}") return hwnd def main(): hwnd = create_window_with_custom_font() if hwnd: # ウインドウを強制的に最前面に表示し、更新を促す # 作成直後のウィンドウは非表示なので、明示的に表示を命令する win32gui.ShowWindow(hwnd, win32con.SW_SHOW) # クライアント領域全体を無効に設定し、WM_PAINTを誘発させる。 # これを呼ばないとウインドウ生成直後の描画処理が行われない時がある。 # 第2引数をNoneにすると全体、第3引数をTrueにすると背景消去も行う win32gui.InvalidateRect(hwnd, None, True) # メッセージキューを待たずにウインドウの描画を即座に更新 win32gui.UpdateWindow(hwnd) # メッセージループ # Windowsから送られてくる「マウスが動いた」「キーが押された」などの # メッセージを絶えず受け取って wnd_proc に振り分ける無限ループ print("メッセージループ開始") win32gui.PumpMessages() print("プロセス終了。") if __name__ == "__main__": main()