123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- # No cancel button.
-
- import threading
- import time
-
- import win32api
- import win32con
- import win32ui
- from pywin.mfc import dialog
- from pywin.mfc.thread import WinThread
-
-
- def MakeProgressDlgTemplate(caption, staticText=""):
- style = (
- win32con.DS_MODALFRAME
- | win32con.WS_POPUP
- | win32con.WS_VISIBLE
- | win32con.WS_CAPTION
- | win32con.WS_SYSMENU
- | win32con.DS_SETFONT
- )
- cs = win32con.WS_CHILD | win32con.WS_VISIBLE
-
- w = 215
- h = 36 # With button
- h = 40
-
- dlg = [
- [caption, (0, 0, w, h), style, None, (8, "MS Sans Serif")],
- ]
-
- s = win32con.WS_TABSTOP | cs
-
- dlg.append([130, staticText, 1000, (7, 7, w - 7, h - 32), cs | win32con.SS_LEFT])
-
- # dlg.append([128,
- # "Cancel",
- # win32con.IDCANCEL,
- # (w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
-
- return dlg
-
-
- class CStatusProgressDialog(dialog.Dialog):
- def __init__(self, title, msg="", maxticks=100, tickincr=1):
- self.initMsg = msg
- templ = MakeProgressDlgTemplate(title, msg)
- dialog.Dialog.__init__(self, templ)
- self.maxticks = maxticks
- self.tickincr = tickincr
- self.pbar = None
-
- def OnInitDialog(self):
- rc = dialog.Dialog.OnInitDialog(self)
- self.static = self.GetDlgItem(1000)
- self.pbar = win32ui.CreateProgressCtrl()
- self.pbar.CreateWindow(
- win32con.WS_CHILD | win32con.WS_VISIBLE, (10, 30, 310, 44), self, 1001
- )
- self.pbar.SetRange(0, self.maxticks)
- self.pbar.SetStep(self.tickincr)
- self.progress = 0
- self.pincr = 5
- return rc
-
- def Close(self):
- self.EndDialog(0)
-
- def SetMaxTicks(self, maxticks):
- if self.pbar is not None:
- self.pbar.SetRange(0, maxticks)
-
- def Tick(self):
- if self.pbar is not None:
- self.pbar.StepIt()
-
- def SetTitle(self, text):
- self.SetWindowText(text)
-
- def SetText(self, text):
- self.SetDlgItemText(1000, text)
-
- def Set(self, pos, max=None):
- if self.pbar is not None:
- self.pbar.SetPos(pos)
- if max is not None:
- self.pbar.SetRange(0, max)
-
-
- # a progress dialog created in a new thread - especially suitable for
- # console apps with no message loop.
- MYWM_SETTITLE = win32con.WM_USER + 10
- MYWM_SETMSG = win32con.WM_USER + 11
- MYWM_TICK = win32con.WM_USER + 12
- MYWM_SETMAXTICKS = win32con.WM_USER + 13
- MYWM_SET = win32con.WM_USER + 14
-
-
- class CThreadedStatusProcessDialog(CStatusProgressDialog):
- def __init__(self, title, msg="", maxticks=100, tickincr=1):
- self.title = title
- self.msg = msg
- self.threadid = win32api.GetCurrentThreadId()
- CStatusProgressDialog.__init__(self, title, msg, maxticks, tickincr)
-
- def OnInitDialog(self):
- rc = CStatusProgressDialog.OnInitDialog(self)
- self.HookMessage(self.OnTitle, MYWM_SETTITLE)
- self.HookMessage(self.OnMsg, MYWM_SETMSG)
- self.HookMessage(self.OnTick, MYWM_TICK)
- self.HookMessage(self.OnMaxTicks, MYWM_SETMAXTICKS)
- self.HookMessage(self.OnSet, MYWM_SET)
- return rc
-
- def _Send(self, msg):
- try:
- self.PostMessage(msg)
- except win32ui.error:
- # the user closed the window - but this does not cancel the
- # process - so just ignore it.
- pass
-
- def OnTitle(self, msg):
- CStatusProgressDialog.SetTitle(self, self.title)
-
- def OnMsg(self, msg):
- CStatusProgressDialog.SetText(self, self.msg)
-
- def OnTick(self, msg):
- CStatusProgressDialog.Tick(self)
-
- def OnMaxTicks(self, msg):
- CStatusProgressDialog.SetMaxTicks(self, self.maxticks)
-
- def OnSet(self, msg):
- CStatusProgressDialog.Set(self, self.pos, self.max)
-
- def Close(self):
- assert self.threadid, "No thread!"
- win32api.PostThreadMessage(self.threadid, win32con.WM_QUIT, 0, 0)
-
- def SetMaxTicks(self, maxticks):
- self.maxticks = maxticks
- self._Send(MYWM_SETMAXTICKS)
-
- def SetTitle(self, title):
- self.title = title
- self._Send(MYWM_SETTITLE)
-
- def SetText(self, text):
- self.msg = text
- self._Send(MYWM_SETMSG)
-
- def Tick(self):
- self._Send(MYWM_TICK)
-
- def Set(self, pos, max=None):
- self.pos = pos
- self.max = max
- self._Send(MYWM_SET)
-
-
- class ProgressThread(WinThread):
- def __init__(self, title, msg="", maxticks=100, tickincr=1):
- self.title = title
- self.msg = msg
- self.maxticks = maxticks
- self.tickincr = tickincr
- self.dialog = None
- WinThread.__init__(self)
- self.createdEvent = threading.Event()
-
- def InitInstance(self):
- self.dialog = CThreadedStatusProcessDialog(
- self.title, self.msg, self.maxticks, self.tickincr
- )
- self.dialog.CreateWindow()
- try:
- self.dialog.SetForegroundWindow()
- except win32ui.error:
- pass
- self.createdEvent.set()
- return WinThread.InitInstance(self)
-
- def ExitInstance(self):
- return 0
-
-
- def StatusProgressDialog(title, msg="", maxticks=100, parent=None):
- d = CStatusProgressDialog(title, msg, maxticks)
- d.CreateWindow(parent)
- return d
-
-
- def ThreadedStatusProgressDialog(title, msg="", maxticks=100):
- t = ProgressThread(title, msg, maxticks)
- t.CreateThread()
- # Need to run a basic "PumpWaitingMessages" loop just incase we are
- # running inside Pythonwin.
- # Basic timeout incase things go terribly wrong. Ideally we should use
- # win32event.MsgWaitForMultipleObjects(), but we use a threading module
- # event - so use a dumb strategy
- end_time = time.time() + 10
- while time.time() < end_time:
- if t.createdEvent.isSet():
- break
- win32ui.PumpWaitingMessages()
- time.sleep(0.1)
- return t.dialog
-
-
- def demo():
- d = StatusProgressDialog("A Demo", "Doing something...")
- import win32api
-
- for i in range(100):
- if i == 50:
- d.SetText("Getting there...")
- if i == 90:
- d.SetText("Nearly done...")
- win32api.Sleep(20)
- d.Tick()
- d.Close()
-
-
- def thread_demo():
- d = ThreadedStatusProgressDialog("A threaded demo", "Doing something")
- import win32api
-
- for i in range(100):
- if i == 50:
- d.SetText("Getting there...")
- if i == 90:
- d.SetText("Nearly done...")
- win32api.Sleep(20)
- d.Tick()
- d.Close()
-
-
- if __name__ == "__main__":
- thread_demo()
- # demo()
|