threadedgui.py
5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Demo of using just windows, without documents and views.
# Also demo of a GUI thread, pretty much direct from the MFC C++ sample MTMDI.
import win32ui
import win32con
import win32api
import timer
from pywin.mfc import window, docview, thread
from pywin.mfc.thread import WinThread
WM_USER_PREPARE_TO_CLOSE = win32con.WM_USER + 32
# font is a dictionary in which the following elements matter:
# (the best matching font to supplied parameters is returned)
# name string name of the font as known by Windows
# size point size of font in logical units
# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD)
# italic boolean; true if set to anything but None
# underline boolean; true if set to anything but None
# This window is a child window of a frame. It is not the frame window itself.
class FontWindow(window.Wnd):
def __init__(self, text = 'Python Rules!'):
window.Wnd.__init__(self)
self.text = text
self.index = 0
self.incr = 1
self.width = self.height = 0
self.ChangeAttributes()
# set up message handlers
def Create(self, title, style, rect, parent):
classStyle = win32con.CS_HREDRAW | win32con.CS_VREDRAW
className = win32ui.RegisterWndClass(classStyle, 0, win32con.COLOR_WINDOW+1, 0)
self._obj_ = win32ui.CreateWnd()
self._obj_.AttachObject(self)
self._obj_.CreateWindow(className, title, style, rect, parent, win32ui.AFX_IDW_PANE_FIRST)
self.HookMessage (self.OnSize, win32con.WM_SIZE)
self.HookMessage (self.OnPrepareToClose, WM_USER_PREPARE_TO_CLOSE)
self.HookMessage (self.OnDestroy, win32con.WM_DESTROY)
self.timerid = timer.set_timer (100, self.OnTimer)
self.InvalidateRect()
def OnDestroy (self, msg):
timer.kill_timer(self.timerid)
def OnTimer(self, id, timeVal):
self.index = self.index + self.incr
if self.index > len(self.text):
self.incr = -1
self.index = len(self.text)
elif self.index < 0:
self.incr = 1
self.index = 0
self.InvalidateRect()
def OnPaint (self):
# print "Paint message from thread", win32api.GetCurrentThreadId()
dc, paintStruct = self.BeginPaint()
self.OnPrepareDC(dc, None)
if (self.width == 0 and self.height == 0):
left, top, right, bottom = self.GetClientRect()
self.width = right - left
self.height = bottom - top
x, y = self.width // 2, self.height // 2
dc.TextOut (x, y, self.text[:self.index])
self.EndPaint(paintStruct)
def ChangeAttributes(self):
font_spec = {'name':'Arial', 'height':42}
self.font = win32ui.CreateFont (font_spec)
def OnPrepareToClose(self, params):
self.DestroyWindow()
def OnSize (self, params):
lParam = params[3]
self.width = win32api.LOWORD(lParam)
self.height = win32api.HIWORD(lParam)
def OnPrepareDC (self, dc, printinfo):
# Set up the DC for forthcoming OnDraw call
dc.SetTextColor (win32api.RGB(0,0,255))
dc.SetBkColor (win32api.GetSysColor (win32con.COLOR_WINDOW))
dc.SelectObject (self.font)
dc.SetTextAlign (win32con.TA_CENTER | win32con.TA_BASELINE)
class FontFrame(window.MDIChildWnd):
def __init__(self):
pass # Dont call base class doc/view version...
def Create(self, title, rect = None, parent = None):
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
self._obj_ = win32ui.CreateMDIChild()
self._obj_.AttachObject(self)
self._obj_.CreateWindow(None, title, style, rect, parent)
rect = self.GetClientRect()
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
self.child = FontWindow("Not threaded")
self.child.Create("FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self)
class TestThread(WinThread):
def __init__(self, parentWindow):
self.parentWindow = parentWindow
self.child = None
WinThread.__init__(self)
def InitInstance(self):
rect = self.parentWindow.GetClientRect()
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
self.child = FontWindow()
self.child.Create("FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self.parentWindow)
self.SetMainFrame(self.child)
return WinThread.InitInstance(self)
def ExitInstance(self):
return 0
class ThreadedFontFrame(window.MDIChildWnd):
def __init__(self):
pass # Dont call base class doc/view version...
self.thread = None
def Create(self, title, rect = None, parent = None):
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
self._obj_ = win32ui.CreateMDIChild()
self._obj_.CreateWindow(None, title, style, rect, parent)
self._obj_.HookMessage(self.OnDestroy, win32con.WM_DESTROY)
self._obj_.HookMessage (self.OnSize, win32con.WM_SIZE)
self.thread = TestThread(self)
self.thread.CreateThread()
def OnSize(self, msg):
pass
def OnDestroy(self, msg):
win32ui.OutputDebugString("OnDestroy\n")
if self.thread and self.thread.child:
child = self.thread.child
child.SendMessage(WM_USER_PREPARE_TO_CLOSE, 0, 0)
win32ui.OutputDebugString("Destroyed\n")
def Demo():
f = FontFrame()
f.Create("Font Demo")
def ThreadedDemo():
rect = win32ui.GetMainFrame().GetMDIClient().GetClientRect()
rect = rect[0], int(rect[3]*3/4), int(rect[2]/4), rect[3]
incr = rect[2]
for i in range(4):
if i==0:
f = FontFrame()
title = "Not threaded"
else:
f = ThreadedFontFrame()
title = "Threaded GUI Demo"
f.Create(title, rect)
rect = rect[0] + incr, rect[1], rect[2]+incr, rect[3]
# Givem a chance to start
win32api.Sleep(100)
win32ui.PumpWaitingMessages()
if __name__=='__main__':
import demoutils
if demoutils.NeedGoodGUI():
ThreadedDemo()
# Demo()