Clock freezes - wx.python glib problem - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: Clock freezes - wx.python glib problem (/thread-5439.html) |
Clock freezes - wx.python glib problem - strongheart - Oct-03-2017 new to python and wx, I wrote a simple clock program. It works well for a while but eventually the graphics freeze. Internally it still runs, but the graphics cease to update. It unfreezes if I resize the frame and the print buffer releases this error message: The id keeps increasing.My guess is that the garbage collector loses track of dc. What did I do wrong? xClock.py # -*- coding: utf-8 -*- # import wx import threading import time from datetime import datetime #return 2 digit string from int def fix(n): s=repr(n) if n<10: s='0'+s return s class xClock(wx.Window): def __init__(self,p): super(xClock, self).__init__(p) self.W=400 self.H=100 self.SetSize(wx.Size(self.W,self.H)) self.R=195 self.img=None self.DRAWN=False self.timeText="" self.SetForegroundColour(wx.BLUE) self.font=self.GetFont() w,h,d,e =self.GetFullTextExtent('00:00:00') FE=[w,h,d,e] print ('GetFullTextExtent '+ repr(FE)) self.font.SetPointSize(70) self.SetFont(self.font) w,h,d,e =self.GetFullTextExtent('00:00:00') FE=[w,h,d,e] print ('GetFullTextExtent '+ repr(FE)) wx.EVT_PAINT(self,self.OnPaint) wx.EVT_WINDOW_DESTROY=self.stop() self.RUNNING=False self.ticker=None self.start() def OnPaint(self, evt): if self.img==None: self.draw() return False dc=wx.PaintDC(self) dc.BeginDrawing() w,h=self.img.GetSize() W,H=self.GetSize() x=(W-w)//2 y=(H-h)//2 dc.DrawBitmap(self.img,x,y) dc.EndDrawing() return True def draw(self): if self.img==None: self.img=wx.EmptyBitmap(self.W,self.H) self.DRAWN=False now=datetime.now() h=fix(now.hour) m=fix(now.minute) s=fix(now.second) t=h+":"+m+":"+s self.timeText=t dc = wx.MemoryDC() dc.SelectObject(self.img) dc.BeginDrawing() F=self.GetFont() dc.SetFont(F) w,h=dc.GetTextExtent(t) W,H=self.img.GetSize() x0=(self.W-w)//2 y0=(self.H-h)//2 dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID)) dc.Clear() dc.SetTextForeground(wx.BLUE) dc.DrawText(t,x0,y0) self.DRAWN=True dc.EndDrawing() self.Refresh() def start(self): pass if self.ticker ==None or not self.ticker.is_alive(): self.ticker=threading.Thread(None, self.run, "Ticker") print("start() "+self.ticker.getName()) self.ticker.start() def stop(self): self.RUNNING=False time.sleep(2) def run(self): self.RUNNING=True delay=1 print("RUNNING") while self.RUNNING: self.draw() self.Refresh(False) time.sleep(delay) #T=threading.currentThread().getName() # just curious # print(self.timeText+' '), # prove it runs when frozen print(self.timeText) self.RUNNING=False__init__.py #!/usr/bin/python # -*- coding: utf-8 -*- import wx from xClock import xClock class XCFrame(wx.Frame): def __init__(self,parent): super(XCFrame, self).__init__(parent) self.SetTitle("XAOS CLOCK") xcp=xClock(self) sizer=wx.BoxSizer(wx.VERTICAL) sizer.Add(xcp,1,wx.EXPAND,wx.ALL) self.SetBackgroundColour(wx.CYAN) self.SetSizer(sizer) class xaosApp(wx.App): def __init__(self): super(xaosApp, self).__init__() xcf=XCFrame(None) xcf.Show() if __name__=='__main__': app=xaosApp() app.MainLoop() RE: Clock freezes - wx.python glib problem - Larz60+ - Oct-03-2017 wx.PaintDC was depreciated with the release of wxpython phoenix. I was trying to run, but cannot in python 3.6 Since you're new to python, why not use the latest version? RE: Clock freezes - wx.python glib problem - snippsat - Oct-04-2017 There is own wx.Timer() that handles stuff like clock, so then is no need to use threading which can freeze GUI if used wrong(interfere with GUI own main loop). Here a analog clock example rewritten for Phoenix and Python 3.6. See that it call wx.Timer(). import wx import time class Example(wx.Frame): def __init__(self, *args, **kw): super().__init__(*args, **kw) self.Bind(wx.EVT_PAINT, self.OnPaint) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) self.timer.Start(1000) self.Show(True) def Draw(self, dc): t = time.localtime(time.time()) st = time.strftime("%I:%M:%S", t) dc.SetBackground(wx.Brush(self.GetBackgroundColour())) dc.Clear() dc.SetFont(wx.Font(30, wx.SWISS, wx.NORMAL, wx.NORMAL)) tw, th = dc.GetTextExtent(st) dc.DrawText(st, 20, 20) def OnTimer(self, evt): dc = wx.BufferedDC(wx.ClientDC(self)) self.Draw(dc) def OnPaint(self, evt): dc = wx.BufferedPaintDC(self) self.Draw(dc) if __name__ == '__main__': ex = wx.App() Example(None) ex.MainLoop()As a note Threading and GUI can be difficult,that why most GUI toolkit has own method to deal with this. Example for wxPython:
RE: Clock freezes - wx.python glib problem - strongheart - Oct-10-2017 Thank-you folks, I went with the buffered paint DC and everything is smooth and solid. Just guessing what was going wrong... A) repainting an image every second and making a new dc probably jammed up the garbage collector ? B) maybe the system tried to paint the image while it was being redrawn ? Still a learning project in progress..... ###ClockProps.py # -*- coding: utf-8 -*- import wx import DClockPane # may not need to import BackgroundColor=wx.BLACK TextColor=wx.CYAN Draw_Frame=True #False frame=wx.Rect(0,0,0,0) frame_color=wx.GREEN FontSize=100 FontFamily=wx.FONTFAMILY_DEFAULT Show_Seconds=True Show_Blink=False # annoyint, but could be useful as a flag Time_sep=':' Time_blink='.' # if Show_Blink then every half second Time_sep='.' TimeFormat_hour=24 # might never use this, but it should be an option # optional 'features' Shadow_Effect=True Shadow_color=wx.LIGHT_GREY Shadow_x=3 Shadow_y=3 ### DClockPane # -*- coding: utf-8 -*- import wx import time import ClockProps def fix(n): N=repr(n) if n<10: N="0"+N return N def ts(c=':'): b=" " t=time.localtime() h=fix(t[3]) m=fix(t[4]) s=fix(t[5]) return b+h+c+m+c+s+b class DClockPane(wx.Window): def __init__(self, p): super(DClockPane, self).__init__(p) font=self.GetFont() font.SetPointSize(ClockProps.FontSize) self.SetFont(font) self.SetBackgroundColour(ClockProps.BackgroundColor) w,h=self.textSize(font) print ("text size="+ repr([w,h] )) self.SetSize(wx.Size(w,h)) self.drawFrame=ClockProps.Draw_Frame self.Box=None if self.drawFrame: ClockProps.frame=wx.Rect(0,0,w,h) self.Box=ClockProps.frame self.showSecs=ClockProps.Show_Seconds self.textColor=ClockProps.TextColor self.BLINK=ClockProps.Time_blink self.DELAY=1000 if self.BLINK: self.DELAY=500 self.TOCK=False self.SHADOW=ClockProps.Shadow_Effect self.Bind(wx.EVT_PAINT, self.OnPaint) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER,self.run,self.timer ) self.timer.Start(self.DELAY) def draw(self, dc): dc.SetBackground(wx.Brush(self.GetBackgroundColour())) dc.Clear() #dc.SetFont(wx.Font(30, wx.SWISS, wx.NORMAL, wx.NORMAL)) c=':' if self.BLINK: self.TOCK= not self.TOCK if self.TOCK: c='.' st=ts(c) tw, th = dc.GetTextExtent(st) w,h =self.GetSize() x=(w-tw)/2 y=(h-th)/2 if self.drawFrame: dc.SetPen(wx.Pen( ClockProps.frame_color )) dc.DrawRectanglePointSize( wx.Point(x,y), self.Box.GetSize()) if self.SHADOW: dc.SetTextForeground(ClockProps.Shadow_color) dc.DrawText(st, x+ClockProps.Shadow_x, y+ClockProps.Shadow_y) dc.SetTextForeground(wx.CYAN) #(wx.Brush(wx.CYAN, wx.SOLID)) dc.DrawText(st, x, y) def run(self,e): dc = wx.BufferedDC(wx.ClientDC(self)) self.draw(dc) def OnPaint(self, e): """ paint the buffer """ dc = wx.BufferedPaintDC(self) self.draw(dc) def textSize(self, font): if font==None: font=self.GetFont() #z=font.GetSize() dc=wx.ClientDC(self) x,y=dc.GetTextExtent(" 88:88:88 ") return wx.Size(x,y) #__init__.py import wx from DClockPane import DClockPane class ClockFrame(wx.Frame): def __init__(self,p): super(ClockFrame, self).__init__(None) self.SetTitle("Steve's Clock") self.clock=DClockPane(self) sizer=wx.BoxSizer(wx.VERTICAL) sizer.Add(self.clock,1,wx.EXPAND,wx.ALL) self.SetBackgroundColour(wx.CYAN) self.SetSizer(sizer) class DClock(wx.App): def __init__(self): super(DClock, self).__init__() cf=ClockFrame(None) cf.Show() if __name__=='__main__': app=DClock() app.MainLoop() |