Search code examples
pythonpywin32pywin

how to update windowText in python multiple times?


I have been searching for code to help solve this problem. here is the best answer I could find below.

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()

unfortunately the output is "Hello send by Python via Win32!" and then "something new"

this is a good start but I need "something new" to update to "something new 2" and "something new 3" etc

is there anyway I can display "something new 2" and "something new 3" and so on, from a text file containing "something new" "something new 2" "something new 3" and so on?

the updating "windowText = something new" would be very long if I had to input that over and over so maybe it would be better to display a line of a text file one by one.

so my question is this how can I display text from a text file one line at a time as "something new"

or how can I display "something new 2" "something new 3" etc easily using the current code?


Solution

  • Use SetTimer instead of creating additional threads. Example:

    import win32api, win32con, win32gui
    import timer
    
    windowText = 'Hello send by Python via Win32!'
    hWindow = 0
    
    def main():
        hInstance = win32api.GetModuleHandle()
        className = 'SimpleWin32'
    
        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
        wndClassAtom = win32gui.RegisterClass(wndClass)
    
        hWindow = win32gui.CreateWindow(wndClassAtom,                   
            'Python Win32 Window',
            win32con.WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, 0, 0, hInstance, None)
    
        win32gui.ShowWindow(hWindow, win32con.SW_SHOWNORMAL)
        win32gui.UpdateWindow(hWindow)
        timer.set_timer(1000, customDraw)
        win32gui.PumpMessages()
    
    counter = 0
    def customDraw(timer_id, time):
        global hWindow
        global counter
        global windowText
        if counter > 2:
            counter = 0
        text = ["test 0", "test 1", "test 2"]
        windowText = text[counter]
        counter = counter + 1
        win32gui.InvalidateRect(hWindow, None, True)
    
    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()