status.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # No cancel button.
  2. from pywin.mfc import dialog
  3. from pywin.mfc.thread import WinThread
  4. import threading
  5. import win32ui
  6. import win32con
  7. import win32api
  8. import time
  9. def MakeProgressDlgTemplate(caption, staticText = ""):
  10. style = (win32con.DS_MODALFRAME |
  11. win32con.WS_POPUP |
  12. win32con.WS_VISIBLE |
  13. win32con.WS_CAPTION |
  14. win32con.WS_SYSMENU |
  15. win32con.DS_SETFONT)
  16. cs = (win32con.WS_CHILD |
  17. win32con.WS_VISIBLE)
  18. w = 215
  19. h = 36 # With button
  20. h = 40
  21. dlg = [[caption,
  22. (0, 0, w, h),
  23. style,
  24. None,
  25. (8, "MS Sans Serif")],
  26. ]
  27. s = win32con.WS_TABSTOP | cs
  28. dlg.append([130, staticText, 1000, (7, 7, w-7, h-32), cs | win32con.SS_LEFT])
  29. # dlg.append([128,
  30. # "Cancel",
  31. # win32con.IDCANCEL,
  32. # (w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
  33. return dlg
  34. class CStatusProgressDialog(dialog.Dialog):
  35. def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
  36. self.initMsg = msg
  37. templ = MakeProgressDlgTemplate(title, msg)
  38. dialog.Dialog.__init__(self, templ)
  39. self.maxticks = maxticks
  40. self.tickincr = tickincr
  41. self.pbar = None
  42. def OnInitDialog(self):
  43. rc = dialog.Dialog.OnInitDialog(self)
  44. self.static = self.GetDlgItem(1000)
  45. self.pbar = win32ui.CreateProgressCtrl()
  46. self.pbar.CreateWindow (win32con.WS_CHILD |
  47. win32con.WS_VISIBLE,
  48. (10, 30, 310, 44),
  49. self, 1001)
  50. self.pbar.SetRange(0, self.maxticks)
  51. self.pbar.SetStep(self.tickincr)
  52. self.progress = 0
  53. self.pincr = 5
  54. return rc
  55. def Close(self):
  56. self.EndDialog(0)
  57. def SetMaxTicks(self, maxticks):
  58. if self.pbar is not None:
  59. self.pbar.SetRange(0, maxticks)
  60. def Tick(self):
  61. if self.pbar is not None:
  62. self.pbar.StepIt()
  63. def SetTitle(self, text):
  64. self.SetWindowText(text)
  65. def SetText(self, text):
  66. self.SetDlgItemText(1000, text)
  67. def Set(self, pos, max = None):
  68. if self.pbar is not None:
  69. self.pbar.SetPos(pos)
  70. if max is not None:
  71. self.pbar.SetRange(0, max)
  72. # a progress dialog created in a new thread - especially suitable for
  73. # console apps with no message loop.
  74. MYWM_SETTITLE = win32con.WM_USER+10
  75. MYWM_SETMSG = win32con.WM_USER+11
  76. MYWM_TICK = win32con.WM_USER+12
  77. MYWM_SETMAXTICKS = win32con.WM_USER+13
  78. MYWM_SET = win32con.WM_USER+14
  79. class CThreadedStatusProcessDialog(CStatusProgressDialog):
  80. def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
  81. self.title = title
  82. self.msg = msg
  83. self.threadid = win32api.GetCurrentThreadId()
  84. CStatusProgressDialog.__init__(self, title, msg, maxticks, tickincr)
  85. def OnInitDialog(self):
  86. rc = CStatusProgressDialog.OnInitDialog(self)
  87. self.HookMessage(self.OnTitle, MYWM_SETTITLE)
  88. self.HookMessage(self.OnMsg, MYWM_SETMSG)
  89. self.HookMessage(self.OnTick, MYWM_TICK)
  90. self.HookMessage(self.OnMaxTicks, MYWM_SETMAXTICKS)
  91. self.HookMessage(self.OnSet, MYWM_SET)
  92. return rc
  93. def _Send(self, msg):
  94. try:
  95. self.PostMessage(msg)
  96. except win32ui.error:
  97. # the user closed the window - but this does not cancel the
  98. # process - so just ignore it.
  99. pass
  100. def OnTitle(self, msg):
  101. CStatusProgressDialog.SetTitle(self, self.title)
  102. def OnMsg(self, msg):
  103. CStatusProgressDialog.SetText(self, self.msg)
  104. def OnTick(self, msg):
  105. CStatusProgressDialog.Tick(self)
  106. def OnMaxTicks(self, msg):
  107. CStatusProgressDialog.SetMaxTicks(self, self.maxticks)
  108. def OnSet(self, msg):
  109. CStatusProgressDialog.Set(self, self.pos, self.max)
  110. def Close(self):
  111. assert self.threadid, "No thread!"
  112. win32api.PostThreadMessage(self.threadid, win32con.WM_QUIT, 0, 0)
  113. def SetMaxTicks(self, maxticks):
  114. self.maxticks = maxticks
  115. self._Send(MYWM_SETMAXTICKS)
  116. def SetTitle(self, title):
  117. self.title = title
  118. self._Send(MYWM_SETTITLE)
  119. def SetText(self, text):
  120. self.msg = text
  121. self._Send(MYWM_SETMSG)
  122. def Tick(self):
  123. self._Send(MYWM_TICK)
  124. def Set(self, pos, max = None):
  125. self.pos = pos
  126. self.max = max
  127. self._Send(MYWM_SET)
  128. class ProgressThread(WinThread):
  129. def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
  130. self.title = title
  131. self.msg = msg
  132. self.maxticks = maxticks
  133. self.tickincr = tickincr
  134. self.dialog = None
  135. WinThread.__init__(self)
  136. self.createdEvent = threading.Event()
  137. def InitInstance(self):
  138. self.dialog = CThreadedStatusProcessDialog( self.title, self.msg, self.maxticks, self.tickincr)
  139. self.dialog.CreateWindow()
  140. try:
  141. self.dialog.SetForegroundWindow()
  142. except win32ui.error:
  143. pass
  144. self.createdEvent.set()
  145. return WinThread.InitInstance(self)
  146. def ExitInstance(self):
  147. return 0
  148. def StatusProgressDialog(title, msg = "", maxticks = 100, parent = None):
  149. d = CStatusProgressDialog (title, msg, maxticks)
  150. d.CreateWindow (parent)
  151. return d
  152. def ThreadedStatusProgressDialog(title, msg = "", maxticks = 100):
  153. t = ProgressThread(title, msg, maxticks)
  154. t.CreateThread()
  155. # Need to run a basic "PumpWaitingMessages" loop just incase we are
  156. # running inside Pythonwin.
  157. # Basic timeout incase things go terribly wrong. Ideally we should use
  158. # win32event.MsgWaitForMultipleObjects(), but we use a threading module
  159. # event - so use a dumb strategy
  160. end_time = time.time() + 10
  161. while time.time() < end_time:
  162. if t.createdEvent.isSet():
  163. break
  164. win32ui.PumpWaitingMessages()
  165. time.sleep(0.1)
  166. return t.dialog
  167. def demo():
  168. d = StatusProgressDialog("A Demo", "Doing something...")
  169. import win32api
  170. for i in range(100):
  171. if i == 50:
  172. d.SetText("Getting there...")
  173. if i==90:
  174. d.SetText("Nearly done...")
  175. win32api.Sleep(20)
  176. d.Tick()
  177. d.Close()
  178. def thread_demo():
  179. d = ThreadedStatusProgressDialog("A threaded demo", "Doing something")
  180. import win32api
  181. for i in range(100):
  182. if i == 50:
  183. d.SetText("Getting there...")
  184. if i==90:
  185. d.SetText("Nearly done...")
  186. win32api.Sleep(20)
  187. d.Tick()
  188. d.Close()
  189. if __name__=='__main__':
  190. thread_demo()
  191. #demo()