2016-11-15 21 views
0

WindowsでPythonを使用して非スクロールのテキスト出力ウィンドウを設定しようとしています。Windowsのテキストをwin32gui.DrawTextで更新できない

win32gui.DrawTextを使用してウィンドウにテキストを配置するコード例がいくつか見つかりましたが、初期テキストが配置された後にテキストを追加または変更するものはありません。

DrawTextが呼び出された後にウィンドウのテキストが修正されたことを示すためのドキュメントには何も見当たりませんでしたが、初めてウィンドウがペイントされた後は何も変更できませんでした。

何が欠けていると私はWindowsのテキストを更新することができますか?

ここでは、1秒後にウィンドウのテキストを変更するように変更したChristophe Kellerの "Hello World"の例を示します。 (私が追加されたコードは動作しません。)あなたのコードと3つの問題がありました

import win32api 
import win32con 
import win32gui 
import time 

#Code example modified from: 
#Christophe Keller 
#Hello World in Python using Win32 

# New code: Define global 
g_str_Text = 'Hello send by Python via Win32!' 

def main(): 
    #get instance handle 
    hInstance = win32api.GetModuleHandle() 

    # the class name 
    className = 'SimpleWin32' 

    # create and initialize window class 
    wndClass    = win32gui.WNDCLASS() 
    wndClass.style   = win32con.CS_HREDRAW | win32con.CS_VREDRAW 
    wndClass.lpfnWndProc = wndProc 
    wndClass.hInstance  = hInstance 
    wndClass.hIcon   = win32gui.LoadIcon(0, win32con.IDI_APPLICATION) 
    wndClass.hCursor  = win32gui.LoadCursor(0, win32con.IDC_ARROW) 
    wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH) 
    wndClass.lpszClassName = className 

    # register window class 
    wndClassAtom = None 
    try: 
     wndClassAtom = win32gui.RegisterClass(wndClass) 
    except Exception as e: 
     print (e) 
     raise e 

    hWindow = win32gui.CreateWindow(
     wndClassAtom,     #it seems message dispatching only works with the atom, not the class name 
     'Python Win32 Window', 
     win32con.WS_OVERLAPPEDWINDOW, 
     win32con.CW_USEDEFAULT, 
     win32con.CW_USEDEFAULT, 
     win32con.CW_USEDEFAULT, 
     win32con.CW_USEDEFAULT, 
     0, 
     0, 
     hInstance, 
     None) 

    # Show & update the window 
    win32gui.ShowWindow(hWindow, win32con.SW_SHOWNORMAL) 
    win32gui.UpdateWindow(hWindow) 

    # Dispatch messages 
    win32gui.PumpMessages() 

# New code: Attempt to change the text 1 second later 
    time.sleep(1.0) 
    g_str_Text = 'Something new' 
    win32gui.ShowWindow(hWindow, win32con.SW_SHOWNORMAL) 
    win32gui.UpdateWindow(hWindow) 
    win32gui.PumpMessages() 

def wndProc(hWnd, message, wParam, lParam): 

    if message == win32con.WM_PAINT: 
     hDC, paintStruct = win32gui.BeginPaint(hWnd) 

     rect = win32gui.GetClientRect(hWnd) 
     win32gui.DrawText(
      hDC, 
      g_str_Text, 
      -1, 
      rect, 
      win32con.DT_SINGLELINE | win32con.DT_CENTER | win32con.DT_VCENTER) 

     win32gui.EndPaint(hWnd, paintStruct) 
     return 0 

    elif message == win32con.WM_DESTROY: 
     print ('Being destroyed') 
     win32gui.PostQuitMessage(0) 
     return 0 

    else: 
     return win32gui.DefWindowProc(hWnd, message, wParam, lParam) 

if __name__ == '__main__': 
    main() 

答えて

0

  1. [Activestate] win32gui.PumpMessagesは、ウィンドウは、コードがそれに追従することを意味し、WM_QUITを受けゴマを遮断ですが、 (再描画するはずだった)は、ウィンドウを閉じた後にの後にのみが実行され、そのときにはhWindowハンドルが無効になるため、例外が生成されます。この問題によって、コードが次のコードに実行されることもありませんでした。
  2. どちらのウィンドウも変更されていないため(ウィンドウ領域が無効化であったため)、win32gui.ShowWindow,win32gui.UpdateWindowのいずれも、ウィンドウの再描画をトリガーしません。無効化を強制する典型的なユーザーアクションは、ウィンドウのサイズ変更(最小化/最大化を含む)です。ウィンドウを移動すると、ではなく、が再描画されます。 -
  3. g_str_Text = 'Something new'これは(のバリアント)Pythonの落とし穴だ、あなたはそれがないと思う何をしていません。それが作成されます代わりにグローバルを変更するのではなく、ローカルmainになり、新たなg_str_Textウィンドウを描画するのにwndProcが使用するもの。

問題を解決するには、ウィンドウを再描画するコードを新しいスレッドから実行する必要があります。これを行うために:

  • 新しい機能(customDraw)に入れました。
  • スレッドはwin32gui.PumpMessagesの前にを開始し、1秒間スリープしてからwindowTextの値(注:global)を変更します。
  • これは、ウィンドウが([MSDN] RedrawWindow functionのラッパーである)[ActiveState] win32gui.RedrawWindowを経由して再描画強制:
    • は、その無効化されたクライアント領域(win32con.RDW_INVALIDATE)ウィンドウを通知します。
    • また、古いテキストに新しいテキストを描画しないように、クライアント領域を消去する必要があることを通知します(win32con.RDW_ERASE)。
    • WM_PAINTメッセージをウィンドウに送信します。

はここで上記の変更であなたのスクリプトです - キャメルケースところでである - 私は唯一の命名規則を持っている(例えばwindowTextg_str_Textの名前を変更する)他のいくつかの小さな変更をしたことに注意してくださいないPythonを推奨):

import win32api 
import win32con 
import win32gui 
import time 
import threading 

#Code example modified from: 
#Christophe Keller 
#Hello World in Python using Win32 

# New code: Define global 
windowText = 'Hello send by Python via Win32!' 

def main(): 
    #get instance handle 
    hInstance = win32api.GetModuleHandle() 

    # the class name 
    className = 'SimpleWin32' 

    # create and initialize window class 
    wndClass    = win32gui.WNDCLASS() 
    wndClass.style   = win32con.CS_HREDRAW | win32con.CS_VREDRAW 
    wndClass.lpfnWndProc = wndProc 
    wndClass.hInstance  = hInstance 
    wndClass.hIcon   = win32gui.LoadIcon(0, win32con.IDI_APPLICATION) 
    wndClass.hCursor  = win32gui.LoadCursor(0, win32con.IDC_ARROW) 
    wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH) 
    wndClass.lpszClassName = className 

    # register window class 
    wndClassAtom = None 
    try: 
     wndClassAtom = win32gui.RegisterClass(wndClass) 
    except Exception as e: 
     print (e) 
     raise e 

    hWindow = win32gui.CreateWindow(
     wndClassAtom,     #it seems message dispatching only works with the atom, not the class name 
     'Python Win32 Window', 
     win32con.WS_OVERLAPPEDWINDOW, 
     win32con.CW_USEDEFAULT, 
     win32con.CW_USEDEFAULT, 
     win32con.CW_USEDEFAULT, 
     win32con.CW_USEDEFAULT, 
     0, 
     0, 
     hInstance, 
     None) 

    # Show & update the window 
    win32gui.ShowWindow(hWindow, win32con.SW_SHOWNORMAL) 
    win32gui.UpdateWindow(hWindow) 

    # New code: Create and start the thread 
    thr = threading.Thread(target=customDraw, args=(hWindow,)) 
    thr.setDaemon(False) 
    thr.start() 

    # Dispatch messages 
    win32gui.PumpMessages() 


# New code: Attempt to change the text 1 second later 
def customDraw(hWindow): 
    global windowText 
    time.sleep(1.0) 
    windowText = 'Something new' 
    win32gui.RedrawWindow(hWindow, None, None, win32con.RDW_INVALIDATE | win32con.RDW_ERASE) 


def wndProc(hWnd, message, wParam, lParam): 

    if message == win32con.WM_PAINT: 
     hDC, paintStruct = win32gui.BeginPaint(hWnd) 

     rect = win32gui.GetClientRect(hWnd) 
     win32gui.DrawText(
      hDC, 
      windowText, 
      -1, 
      rect, 
      win32con.DT_SINGLELINE | win32con.DT_CENTER | win32con.DT_VCENTER) 

     win32gui.EndPaint(hWnd, paintStruct) 
     return 0 

    elif message == win32con.WM_DESTROY: 
     print('Being destroyed') 
     win32gui.PostQuitMessage(0) 
     return 0 

    else: 
     return win32gui.DefWindowProc(hWnd, message, wParam, lParam) 

if __name__ == '__main__': 
    main() 
関連する問題