From 3a0b3e5c29a030bc8c11277f72bfa631d544d63b Mon Sep 17 00:00:00 2001 From: Chris Kiehl Date: Sun, 26 Jan 2014 02:43:22 -0500 Subject: [PATCH] Man, I suck at version controll. Added too much to list --- src/app/dialogs/base_window.py | 22 +++++-- src/app/dialogs/basic_config_panel.py | 2 +- src/app/dialogs/controller.py | 23 ++++---- src/app/dialogs/display_main.py | 8 +-- src/app/dialogs/footer.py | 52 +++++++++------- src/app/dialogs/footer.pyc | Bin 4391 -> 4993 bytes src/app/dialogs/header.py | 31 ++++++---- src/app/dialogs/header.pyc | Bin 4252 -> 4725 bytes src/app/dialogs/runtime_display_panel.py | 72 +++++++++++++++++++++++ src/app/dialogs/window.py | 2 +- src/app/images/harwen_monitor.png | Bin 0 -> 21070 bytes src/app/images/image_store.py | 1 + src/app/images/image_store.pyc | Bin 976 -> 1081 bytes src/experiments/thread_interupt.py | 39 ++++++++++++ src/languages/eng.py | 4 +- src/languages/english.json | 5 +- 16 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 src/app/dialogs/runtime_display_panel.py create mode 100644 src/app/images/harwen_monitor.png create mode 100644 src/experiments/thread_interupt.py diff --git a/src/app/dialogs/base_window.py b/src/app/dialogs/base_window.py index 887b1e7..0a639a0 100644 --- a/src/app/dialogs/base_window.py +++ b/src/app/dialogs/base_window.py @@ -15,13 +15,14 @@ import sys import wx import header import footer +from app.dialogs.runtime_display_panel import RuntimeDisplay from app.dialogs.controller import Controller from app.images import image_store from app.dialogs.config_model import Model class BaseWindow(wx.Frame): - def __init__(self, body_panel, model): + def __init__(self, body_panel, model, payload): wx.Frame.__init__( self, parent=None, @@ -31,6 +32,7 @@ class BaseWindow(wx.Frame): ) self._model = model + self._payload = payload self._controller = None @@ -56,9 +58,10 @@ class BaseWindow(wx.Frame): parent=self, size=(30,90)) self.body_panel = BodyPanel(self, self._model) - self.cfg_foot_panel = footer.ConfigFooter(self, self._controller) + self.runtime_display = RuntimeDisplay(self) + self.foot_panel = footer.Footer(self, self._controller) - self.panels = [self.head_panel, self.body_panel, self.cfg_foot_panel] + self.panels = [self.head_panel, self.body_panel, self.foot_panel] # self.main_foot_panel = footer.MainFooter(self, self._controller) # self.main_foot_panel.Hide() @@ -67,8 +70,10 @@ class BaseWindow(wx.Frame): sizer.Add(self.head_panel, 0, wx.EXPAND) self._draw_horizontal_line(sizer) sizer.Add(self.body_panel, 1, wx.EXPAND) + self.runtime_display.Hide() + sizer.Add(self.runtime_display, 1, wx.EXPAND) self._draw_horizontal_line(sizer) - sizer.Add(self.cfg_foot_panel, 0, wx.EXPAND) + sizer.Add(self.foot_panel, 0, wx.EXPAND) self.SetSizer(sizer) def _draw_horizontal_line(self, sizer): @@ -81,13 +86,20 @@ class BaseWindow(wx.Frame): base_frame = self, head_panel = self.head_panel, body_panel = self.body_panel, - footer_panel = self.cfg_foot_panel, + footer_panel = self.foot_panel, model = self._model) def registerControllers(self): for panel in self.panels: panel.RegisterController(self._controller) + def NextPage(self): + self.head_panel.NextPage() + self.foot_panel.NextPage() + self.body_panel.Hide() + self.runtime_display.Show() + self.Layout() + def AttachPayload(self, payload): self._payload = payload diff --git a/src/app/dialogs/basic_config_panel.py b/src/app/dialogs/basic_config_panel.py index e43fa65..07f0803 100644 --- a/src/app/dialogs/basic_config_panel.py +++ b/src/app/dialogs/basic_config_panel.py @@ -10,7 +10,7 @@ import wx import os from app.dialogs.option_reader import OptionReader -class BasicDisplayPanel(wx.Panel, OptionReader): +class RuntimeDisplay(wx.Panel, OptionReader): def __init__(self, parent, **kwargs): wx.Panel.__init__(self, parent, **kwargs) diff --git a/src/app/dialogs/controller.py b/src/app/dialogs/controller.py index 1eeb1ec..6dee2ba 100644 --- a/src/app/dialogs/controller.py +++ b/src/app/dialogs/controller.py @@ -7,6 +7,7 @@ Created on Dec 22, 2013 import wx import sys from app.dialogs.config_model import Model +from multiprocessing.dummy import Pool YES = 5103 NO = 5104 @@ -34,7 +35,7 @@ class Controller(object): self._model = model - def OnConfigCancel(self, event): + def OnCancelButton(self, event): msg = "Are you sure you want to exit?" dlg = wx.MessageDialog(None, msg, "Close Program?", wx.YES_NO) result = dlg.ShowModal() @@ -44,7 +45,7 @@ class Controller(object): self._base.Destroy() sys.exit() - def OnConfigNext(self, event): + def OnStartButton(self, event): cmd_line_args = self._body.GetOptions() if not self._model.IsValidArgString(cmd_line_args): error_msg = self._model.GetErrorMsg(cmd_line_args) @@ -53,21 +54,17 @@ class Controller(object): self._model.AddToArgv(cmd_line_args) self._base.NextPage() self.RunClientCode() - - def RunClientCode(self): - pass - - def AddPayload(self, payload): + + def OnCancelRunButton(self, event): pass - - def OnMainCancel(self, event): - print 'OnMaingCancel pressed!' - def OnMainNext(self, event): - print 'OnCongigNext pressed!' - def ShowArgumentErrorDlg(self, error): a = wx.MessageDialog(None, error, 'Argument Error') a.ShowModal() a.Destroy() + def RunClientCode(self): + pool = Pool(1) + pool.apply_async(self._base._payload) + + diff --git a/src/app/dialogs/display_main.py b/src/app/dialogs/display_main.py index acc7b85..b7f4ec7 100644 --- a/src/app/dialogs/display_main.py +++ b/src/app/dialogs/display_main.py @@ -11,8 +11,8 @@ import threading from app.dialogs.controller import Controller from app.images import image_store from app.dialogs.header import FrameHeader -from app.dialogs.basic_config_panel import BasicDisplayPanel -from app.dialogs.footer import ConfigFooter +from app.dialogs.basic_config_panel import RuntimeDisplay +from app.dialogs.footer import Footer from app.dialogs.advanced_config import AdvancedConfigPanel class MessagePump(object): @@ -78,8 +78,8 @@ class MainWindow(wx.Frame): def _init_components(self): # init components self.head_panel = FrameHeader(image_path=image_store.computer3, parent=self, size=(30,90)) - self.body_panel = BasicDisplayPanel(parent=self) - self.foot_panel = ConfigFooter(self, self._controller) + self.body_panel = RuntimeDisplay(parent=self) + self.foot_panel = Footer(self, self._controller) def _do_layout(self): sizer = wx.BoxSizer(wx.VERTICAL) diff --git a/src/app/dialogs/footer.py b/src/app/dialogs/footer.py index e871e8c..7ed097b 100644 --- a/src/app/dialogs/footer.py +++ b/src/app/dialogs/footer.py @@ -15,26 +15,31 @@ class AbstractFooter(wx.Panel): self.SetMinSize((30, 53)) self._controller = None - - self.cancel_button = self._button('Cancel', wx.ID_CANCEL) - self.next_button = self._button("Start", wx.ID_OK) - + + self._init_components() self._do_layout() + def _init_components(self): + self.cancel_button = self._Button('Cancel', wx.ID_CANCEL) + self.start_button = self._Button("Start", wx.ID_OK) + self.cancel_run_button = self._Button('Cancel', wx.ID_CANCEL) + def _do_layout(self): v_sizer = wx.BoxSizer(wx.VERTICAL) h_sizer = wx.BoxSizer(wx.HORIZONTAL) h_sizer.AddStretchSpacer(1) h_sizer.Add(self.cancel_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20) - h_sizer.Add(self.next_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20) + h_sizer.Add(self.start_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20) v_sizer.AddStretchSpacer(1) v_sizer.Add(h_sizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) + v_sizer.Add(self.cancel_run_button, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.RIGHT, 20) + self.cancel_run_button.Hide() v_sizer.AddStretchSpacer(1) self.SetSizer(v_sizer) - def _button(self,label=None, style=None): + def _Button(self,label=None, style=None): return wx.Button( parent=self, id=-1, @@ -45,9 +50,15 @@ class AbstractFooter(wx.Panel): def RegisterController(self, controller): if self._controller is None: self._controller = controller + + def NextPage(self): + self.cancel_button.Hide() + self.start_button.Hide() + self.cancel_run_button.Show() + self.Layout() -class ConfigFooter(AbstractFooter): +class Footer(AbstractFooter): ''' Footer section used on the configuration screen of the application @@ -60,15 +71,20 @@ class ConfigFooter(AbstractFooter): def __init__(self, parent, controller, **kwargs): AbstractFooter.__init__(self, parent, **kwargs) - self.Bind(wx.EVT_BUTTON, self.OnConfigCancel, self.cancel_button) - self.Bind(wx.EVT_BUTTON, self.OnConfigNext, self.next_button) + self.Bind(wx.EVT_BUTTON, self.OnCancelButton, self.cancel_button) + self.Bind(wx.EVT_BUTTON, self.OnStartButton, self.start_button) + self.Bind(wx.EVT_BUTTON, self.OnCancelRunButton, self.cancel_run_button) + + def OnCancelButton(self, event): + self._controller.OnCancelButton(event) + event.Skip() - def OnConfigCancel(self, event): - self._controller.OnConfigCancel(event) + def OnCancelRunButton(self, event): + self._controller.OnCancelRunButton(event) event.Skip() - def OnConfigNext(self, event): - self._controller.OnConfigNext(event) + def OnStartButton(self, event): + self._controller.OnStartButton(event) event.Skip() @@ -84,18 +100,14 @@ class MainFooter(AbstractFooter): def __init__(self, parent, controller, **kwargs): AbstractFooter.__init__(self, parent, **kwargs) - self.Bind(wx.EVT_BUTTON, self.OnConfigCancel, self.cancel_button) - self.Bind(wx.EVT_BUTTON, self.OnConfigNext, self.next_button) + self.start_button = None + + self.Bind(wx.EVT_BUTTON, self.OnMainCancel, self.cancel_button) def OnMainCancel(self, event): self._controller.OnMainCancel(event) # event.Skip() - def OnMainNext(self, event): - self._controller.OnMainNext(event) - event.Skip() - - diff --git a/src/app/dialogs/footer.pyc b/src/app/dialogs/footer.pyc index 8f6dc3b8390452e897c08fe530206f177f0fae91..2f7f22bfdd72ab9e42faed98b06b1f4c28548b2c 100644 GIT binary patch delta 1714 zcmZ`(OK)3M5T0{i_Vpu4?KYIs7B`{kmD55AX}T$kx~<}b^adR}Rh3FuCbqy%xvt_9 zK~SWCk|ivvvu6vckPr)4u;LdWvG1RNO6(AwZ?4@SQDmRd+?hG^_-5vOJM-nGzI`-SSoPKNOJ=*Xc>W_&s#+RRcX5GEwuh_d#Sx~*>8O;xG8bf`#mi1vwE zK4?FnLm~w(BOEImkw-*v?>y7qH71b*?)Won|5mFfr&!qPB|X#H8hr9-kaQC>v|l+# z2QDj$e1ja005=C2f(8N#OZp=itr7HrA=*3ND+ zl18xCq5UJ@oP(Qb+(IN$r}-zLPTjHho z7pPxMo54tUfCS9~J`?s&cP5x*$6DDl-f9KVn>>@7Yb(ofORp@~n^LN9x@3>MXhxS| zg;v&kovz6;)99K;@AK|XghaWPU%iJF$Y0|#L_wrVs^k>ateRzdPE}RW*8RH5*~k8S z6(AtsrU;I_uu#u}ya8b` z-fw@@UE*s)07I%Mzc|X-TbawRyYPqZYiOl7je_+hkgEN0>b`xN$-M$u;07uTLqD9H z%!ZzXwf|&Js|BoX2}{en8em0%(eNkxL!n}~vrp8v-7CfiY2il71s@77IXZM@gBy~3 z9AOGHAJWK8+Fk1<9hq)}1-x^w*{W?co9nSbR_jT+8KWhTNy4(OC$c6Zaf#kxXV`0F}gbtb0h@s~|^639bq_NCrgkRY?tIpa&{^qOFnzvaaNjA27kH&NHP3{99 zirA|B+8MFq@T3=+jBN0EP3B89$A*}vml`fXbC1tx+NP8|0eT)6E`wYFk&Ys`7RL){ z;k15}1@H2aCoISYPM8Tjd%rNND%`yb9yiUkPYS=y-(VxGvO;(EnY#3~^Wuq3pD~Yk zH~WG8xj45X;n44NG~WUz56e|J!b`NC+->(pP10!3|6^T-Hy-}+J5=U()_yUubV?w+ zj=Old(>@7$RS36n0}4_ydM}0KI)GTz*n|hLhf4-Rg_(561U$)HLa>$uHNC_ahwkF^ F`RAu@5Q+c* delta 1152 zcma)5OHUL*5bmBw@6PNFGq6CGM{wmK1FZ5$Fdpy#7*`%HNiQZ!42bM%2Fajoo1if< z1P&fJxGBAQRgWgdt3N?aJn$R58BfNGRn2Zlj4>u#m8$BmzV7;Jc5m=?uP}dj?#t&j z@r7Tg9rbqEtc*XC9T;pyu(HJt7+Xm&SqcRV@=JUZws`KT&GtFtWyYQ`wq}#xM6k&e z1_`!r=z6kIw{+cU)LmUqv3;f~keM-7jC#;Vljs!Xv+MCjWlPx@mel%=3Jp50V=TtP zG<@arsRUNnZa-9NJBC~4h@ZkduI#EtZNfOn6NiUZO`~JHoqL93WO>%u;Fz0egqTIE zeuN3@O_RmSTn|WdrQwv_E2v+ZP_XB7bcG@}y*O7WuF1K=m1X@-9Z3(~*v5+H-o_t16Q}3b19J$lLTb6AH!vT1a zxE2t4d`~A4i{5l3htyF z&rd3nXm&fk6WxU=H_L}=N5dBG-hxB-6JLUxsUmz2+I-?vbkR%{mr<8*sm>|gb-XsI zH6pI1_?WGTJCP(}NL|t=7m({C*G$8;5a|?JmG;kg#^{DaZ@NQII)W8_Vd-9UzcF%; zw`$YD4D5M}of?rt$C@Kf jy6W0+M>y88s#;4uxL!Acm?SCXD0W_ljZBw0)ZXzMdsVeU diff --git a/src/app/dialogs/header.py b/src/app/dialogs/header.py index 94226c8..7a7709c 100644 --- a/src/app/dialogs/header.py +++ b/src/app/dialogs/header.py @@ -7,6 +7,7 @@ Created on Dec 23, 2013 import wx import imageutil from app.dialogs.segoe_statictext import SegoeText +from app.images import image_store PAD_SIZE = 10 @@ -33,16 +34,19 @@ class FrameHeader(wx.Panel): self.SetMinSize((120, 80)) def _init_components(self, heading, subheading, image_path): - self.header = self._bold_static_text(heading) - self.subheader = wx.StaticText(self, label=subheading) - self.img = self._load_image(image_path) + self._header = self._bold_static_text(heading) + self._subheader = wx.StaticText(self, label=subheading) + self._settings_img = self._load_image(image_path) + self._running_img = self._load_image(image_store.harwen_monitor) def _do_layout(self): vsizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.HORIZONTAL) headings_sizer = self.build_heading_sizer() - sizer.Add(headings_sizer, 1, wx.ALIGN_LEFT | wx.EXPAND | wx.LEFT, PAD_SIZE) - sizer.Add(self.img, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE) + sizer.Add(headings_sizer, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND | wx.LEFT, PAD_SIZE) + sizer.Add(self._settings_img, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE) + sizer.Add(self._running_img, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.RIGHT, PAD_SIZE) + self._running_img.Hide() vsizer.Add(sizer, 1, wx.EXPAND) self.SetSizer(vsizer) @@ -57,8 +61,8 @@ class FrameHeader(wx.Panel): def build_heading_sizer(self): sizer = wx.BoxSizer(wx.VERTICAL) sizer.AddStretchSpacer(1) - sizer.Add(self.header, 1) - sizer.Add(self.subheader, 1) + sizer.Add(self._header, 0) + sizer.Add(self._subheader, 0) sizer.AddStretchSpacer(1) return sizer @@ -86,12 +90,19 @@ class FrameHeader(wx.Panel): ) return wx.BitmapFromImage(image) - def UpdateImage(self, image): - pass - def RegisterController(self, controller): if self._controller is None: self._controller = controller + + def NextPage(self): + self._header.SetLabel("Running") + self._subheader.SetLabel('Please wait while the application performs its tasks. ' + '\nThis may take a few moments') + self._settings_img.Hide() + self._running_img.Show() + self.Layout() + + diff --git a/src/app/dialogs/header.pyc b/src/app/dialogs/header.pyc index 010ac5b3b56c32f67c0be23bf441a24f2207c2cf..daa28815349a277973c9d1effaad1092e1220389 100644 GIT binary patch delta 1403 zcmah}OK%)S5bmDW?yUEPm6u=1#In$0MLrM^C=v=L7#w1)t=>f<7BHIZw7s+0-7(u8 zEsj=-kP&C1zHs0YA#vjX9QhGkxNzd3hzrLEA#p%_)#GqNVrILxs;0WStLm%z{PG`b zOYW0e<;qu&MUS06F8*J|Qpv-m=U?C~_1Ms7qk!!PjHf=^FR?UWlCwdX9pH0`eazSi zW4HH1mO8A{DnI<-t+Oo-7kUmP8zqM_Ryv=^ufJP$`~bS9`PKP?SIwia>xYmd^OJj# zzis|@uMcL74Sc3c-h%p>9ICfy!);{Pkxg&?I3OM}?NPH(BrZ^(eSufV|Lyg_g z_GOaFiSWpbY&+JVOW#S1&8ObtUX3^?7G1;4~K~!ZB#^?D3tR6Y0JruzWEcKh&^t%rbZ^&N5l}(QbMwu1d}FKK-4gNkuDH3s+wN}enD>KKzGyxQR#wF_%rphIouyJ!$Q`LW z*?l=VO_BK~m@N|)*0Iz)2<2p+SNR5C$6GURlOeV$ymDYT^%=gp6$PXe3g zGe(vN{#h8lXnrVnZ#nG5DMIpW&H~EBQ$u5 zBU%a&vdacuQD6u@8wCFfCCjDMK{g4tIYfbDB>+FRHc_vj}GKC8s#H7)~aPgrA$7>!w$8q zO{-XhT0BPt$XPC+)9L3^O`~BaInM8CJ3a&rh|VSJp^dKH!yrjuqNsZrZ}O&719twb zuU)m(r0s&ni68?(fD?oj5fPyZ395&=|bh_v1 z^d9V&E>#U!H6bz~7SOfeiGaw0mjHc$l~o%e4Z^_Qf3bAW8 zNS@$K1`!aRXfbnouCZkvE5_Vt1e8W2c{$-68_mb@MquL`qgb&>UXPnmye%16k|q)+ z&7{++$Ip_)ArXHV#WEW^o9%$J%M25jiO0kzG&RYt6*@gm38EmzL`x9I5nNT_`HV+q z{jLLj1H`TdT@!Wzx@m4SAts}!4T~(ebPYUdIOM58BnA$Bo#M&I!?#x1@+rO4@yJ@k zX?s$P<2}1PobY(UI0-vD@%8{WzP5MAxW#}@kHZ*fLAatOrm>RR86P55dscnNa{;@m zxyVucmfEva<3qUUbj@Kh&ETO^zbT-v5gNj1sBSEVd8*QtAe4QugAPw6u+LH#nJeM_ z^my?+vm;E-5m75U8Fr0EY{@byui~%tC!u3MbNvL4k3TaFbBs(2UuN7LpzECju_2R>1pE4}vwzJc$1b%^wu%MQ-!q)2NxmcQ%{tc!k6sKOYbn`3pG( zowqyyh+qBZ?ixFBZV*}go~zEXgXG1lcdDL;RP*G?sa7O|mJCteU~&ud`4y94dAOAy zxnMeulcL{ovW_0`IukD4Xhd7BMuQgqF@MFCQyj{LrJ(pn7#0dX*ReF0_L|cy?H^?& Bi6H<0 diff --git a/src/app/dialogs/runtime_display_panel.py b/src/app/dialogs/runtime_display_panel.py new file mode 100644 index 0000000..0041cf1 --- /dev/null +++ b/src/app/dialogs/runtime_display_panel.py @@ -0,0 +1,72 @@ +''' +Created on Dec 23, 2013 + +@author: Chris +''' + +import wx +import sys +import Queue +import threading +from model.i18n import I18N + +class MessagePump(object): + def __init__(self, queue): + self.queue = queue + self.stdout = sys.stdout + + # Overrides stdout's write method + def write(self, text): + if text != '': + self.queue.put(text) + + +class Listener(threading.Thread): + def __init__(self, queue, textbox): + threading.Thread.__init__(self) + self.queue = queue + self.update_text = lambda x: textbox.AppendText(x) + + def run(self): + while True: + try: + stdout_msg = self.queue.get(timeout=1) + if stdout_msg != '': + self.update_text(stdout_msg) + except Exception as e: + pass # Timeout. Aint nobody care 'bout dat + +class RuntimeDisplay(wx.Panel): + def __init__(self, parent, **kwargs): + wx.Panel.__init__(self, parent, **kwargs) + + self._translator = I18N() + + self._init_properties() + self._init_components() + self._do_layout() + + self.queue = Queue.Queue() + _stdout = sys.stdout + sys.stdout = MessagePump(self.queue) + listener = Listener(self.queue, self.cmd_textbox) + listener.start() + + def _init_properties(self): + self.SetBackgroundColour('#F0F0F0') + + def _init_components(self): + self.text = wx.StaticText(self, label=self._translator["status"]) + self.cmd_textbox = wx.TextCtrl( + self, -1, "", + style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH) + + def _do_layout(self): + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.AddSpacer(10) + sizer.Add(self.text, 0, wx.LEFT, 30) + sizer.AddSpacer(10) + sizer.Add(self.cmd_textbox, 1, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 30) + sizer.AddSpacer(20) + self.SetSizer(sizer) + \ No newline at end of file diff --git a/src/app/dialogs/window.py b/src/app/dialogs/window.py index d1497c4..663c1f3 100644 --- a/src/app/dialogs/window.py +++ b/src/app/dialogs/window.py @@ -34,7 +34,7 @@ from app.dialogs import argparse_test_data def WithAdvancedOptions(parser, payload): app = wx.App(False) model = Model(parser) - frame = BaseWindow(advanced_config.AdvancedConfigPanel, model) + frame = BaseWindow(advanced_config.AdvancedConfigPanel, model, payload) frame.Show(True) # Show the frame. app.MainLoop() diff --git a/src/app/images/harwen_monitor.png b/src/app/images/harwen_monitor.png new file mode 100644 index 0000000000000000000000000000000000000000..36dece121894c2a3eb15ddb36a3b9c4e074cc7a0 GIT binary patch literal 21070 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 E02E#za{vGU delta 77 zcmdnVae-Z$`7#)yCbhpY{3 diff --git a/src/experiments/thread_interupt.py b/src/experiments/thread_interupt.py new file mode 100644 index 0000000..41e1990 --- /dev/null +++ b/src/experiments/thread_interupt.py @@ -0,0 +1,39 @@ +''' +Created on Jan 26, 2014 + +@author: Chris +''' + +import time +import threading +from multiprocessing import Process + +class MyClass(threading.Thread): + ''' + classdocs + ''' + def __init__(self): + threading.Thread.__init__(self) + self.start_time = time.time() + + def run(self): + while time.time() - self.start_time < 10: + pass + + def throw_exception(self): + raise KeyboardInterrupt + + +if __name__ == '__main__': + a = MyClass() + a.start() + + time.sleep(2) + a.exit() + time.sleep(2) + print a.is_alive() + + a.join() + + + \ No newline at end of file diff --git a/src/languages/eng.py b/src/languages/eng.py index 75d5f5b..6614d89 100644 --- a/src/languages/eng.py +++ b/src/languages/eng.py @@ -17,8 +17,8 @@ if __name__ == '__main__': 'optional_args_msg':'Optional Arguments', 'running':'Running', "sure_you_want_to_exit":"Are you sure you want to exit?", - 'close_program': 'Close Program?' - + 'close_program': 'Close Program?', + 'status':'Status' } with open('english.json', 'wb') as f: diff --git a/src/languages/english.json b/src/languages/english.json index f93374f..bd4882d 100644 --- a/src/languages/english.json +++ b/src/languages/english.json @@ -1,9 +1,12 @@ { "cancel": "Cancel", + "close_program": "Close Program?", "next": "Next", "optional_args_msg": "Optional Arguments", "required_args_msg": "Required Arguments", "running": "Running", "settings": "Settings", - "simple_config": "Enter Command Line Arguments" + "simple_config": "Enter Command Line Arguments", + "status": "Status", + "sure_you_want_to_exit": "Are you sure you want to exit?" } \ No newline at end of file