Thread: [Pyobjc-dev] simple animation w/ NSTimer
Brought to you by:
ronaldoussoren
|
From: Carl B. <car...@gm...> - 2008-03-30 23:03:52
|
I'm a physics grad student (not a coder) wanting to put together a slick
realtime physics simulation for my statistical mechanics class. (Simulating
the 2D Ising model for ferromagnets in case anyone cares).
Anyway, to start, I'm just trying to get a rectangle to change colors
periodically. Why doesn't this work?
import objc
from Foundation import *
from AppKit import *
from PyObjCTools import NibClassBuilder, AppHelper
from Quartz import NSColor
NibClassBuilder.extractClasses("MainMenu")
# class defined in MainMenu.nib
class Lattice(NibClassBuilder.AutoBaseClass):
# the actual base class is NSView
color = NSColor.redColor()
toggle = 0
rect = NSMakeRect(40,40,40,40)
def drawRect_(self,frameRect):
NSEraseRect(self.rect)
self.color.setFill()
NSRectFill(self.rect)
def start_(self, sender):
self.timer=NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats
_(1.0,self,self.tick,None,True)
def tick(self,timer):
self.toggle = (self.toggle+1)%2
if self.toggle:
self.color = NSColor.blueColor()
else:
self.color = NSColor.redColor()
self.display()
if __name__ == "__main__":
AppHelper.runEventLoop()
The rectangle is drawn just fine at the beginning, but the timer doesn't
seem to actually invoke drawRect_. I'm probably just not understanding how
to properly use display()? Let me know if I'm being annoying and should just
post to a different mailing list.
Thanks,
Carl
|
|
From: Carl B. <car...@gm...> - 2008-03-31 15:10:50
|
Hey John, thanks for the reply. I implemented your changes, but the display
is still not being refreshed. I put a print statement inside tick_(...) and
drawRect_(...). When the timer starts, the print statement inside the tick
method is called right on cue every second. The print statement in drawRect,
however, is never called, despite my self.display() line inside tick.
On Mon, Mar 31, 2008 at 3:45 AM, John Buckley <nho...@go...>
wrote:
> Hi Carl,
> You don't pass in the function object when specifying Objective-C methods,
> but a method "selector", which in Python land is just a string (in
> Objective-C selectors have the type SEL, which may or may not also be a
> string). Be careful to fully specify the selector by including the colon for
> each argument e.g.
>
> NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
> 1.0,self,'tick:',None,True)
>
> Note that in the Python method definition the colon is replaced by an
> underscore. So in Objective-C your 'tick' method would look like:
>
> - (void)tick:(NSTimer*)timer
> {
> // Implemenation here
> }
>
> In Python this must be translated to:
>
> def tick_(self, timer):
> # implementation here
>
> However the "selector" string must always use the Objective-C version i.e.
> with the colon.
>
> Regards,
>
> John
> ____________________
>
> Dr. John Buckley
> nho...@gm...
>
> www.olivetoast.com
>
> Mac OS X Leopard
> ____________________
>
> On 31 Mar 2008, at 00:03, Carl Bauer wrote:
>
> I'm a physics grad student (not a coder) wanting to put together a slick
> realtime physics simulation for my statistical mechanics class. (Simulating
> the 2D Ising model for ferromagnets in case anyone cares).
>
> Anyway, to start, I'm just trying to get a rectangle to change colors
> periodically. Why doesn't this work?
>
> import objc
> from Foundation import *
> from AppKit import *
> from PyObjCTools import NibClassBuilder, AppHelper
> from Quartz import NSColor
>
> NibClassBuilder.extractClasses("MainMenu")
>
> # class defined in MainMenu.nib
> class Lattice(NibClassBuilder.AutoBaseClass):
> # the actual base class is NSView
> color = NSColor.redColor()
> toggle = 0
> rect = NSMakeRect(40,40,40,40)
>
> def drawRect_(self,frameRect):
> NSEraseRect(self.rect)
> self.color.setFill()
> NSRectFill(self.rect)
>
> def start_(self, sender):
>
> self.timer=NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats
> _(1.0,self,self.tick,None,True)
>
> def tick(self,timer):
> self.toggle = (self.toggle+1)%2
> if self.toggle:
> self.color = NSColor.blueColor()
> else:
> self.color = NSColor.redColor()
> self.display()
>
> if __name__ == "__main__":
> AppHelper.runEventLoop()
>
> The rectangle is drawn just fine at the beginning, but the timer doesn't
> seem to actually invoke drawRect_. I'm probably just not understanding how
> to properly use display()? Let me know if I'm being annoying and should just
> post to a different mailing list.
>
> Thanks,
> Carl
> -------------------------------------------------------------------------
> Check out the new SourceForge.net Marketplace.
> It's the best place to buy or sell services for
> just about anything Open Source.
>
> http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace_______________________________________________
> Pyobjc-dev mailing list
> Pyo...@li...
> https://lists.sourceforge.net/lists/listinfo/pyobjc-dev
>
>
>
|
|
From: David B. <db3...@gm...> - 2008-03-31 17:30:17
|
"Carl Bauer" <car...@gm...> writes: > Hey John, thanks for the reply. I implemented your changes, but the display > is still not being refreshed. I put a print statement inside tick_(...) and > drawRect_(...). When the timer starts, the print statement inside the tick > method is called right on cue every second. The print statement in drawRect, > however, is never called, despite my self.display() line inside tick. I suspect this is more a Cocoa issue than a PyObjC one so more Cocoa oriented lists/resources might help further. Is your Lattice class a direct subclass of NSView? If so, then I think you may need to return YES from the isOpaque method (NSView returns NO). Without that, perhaps your subclass is never getting a chance to draw anything if there is no opaque starting point for that region of the display. Of course, you should then also handle clearing your own background in addition to any foreground drawing. -- David |
|
From: Bob V. <pyo...@bo...> - 2008-03-31 22:25:55
|
On Mar 31, 2008, at 8:10 AM, Carl Bauer wrote: > Hey John, thanks for the reply. I implemented your changes, but the > display is still not being refreshed. I put a print statement inside > tick_(...) and drawRect_(...). When the timer starts, the print > statement inside the tick method is called right on cue every > second. The print statement in drawRect, however, is never called, > despite my self.display() line inside tick. I suggest invoking self.setNeedsDisplay_(True) before self.display(). Also, read the Cocoa drawing Guide available from http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/CocoaDrawingGuide.pdf Ciao, Bob |
|
From: Carl B. <car...@gm...> - 2008-03-31 22:55:03
|
Thanks guys. I have read the drawing guide, Bob. It was okay. I guess I need to read the guide on Views as well before I ask any more questions. Till then... -Carl On Mon, Mar 31, 2008 at 4:25 PM, Bob Vadnais <pyo...@bo...> wrote: > On Mar 31, 2008, at 8:10 AM, Carl Bauer wrote: > > > Hey John, thanks for the reply. I implemented your changes, but the > > display is still not being refreshed. I put a print statement inside > > tick_(...) and drawRect_(...). When the timer starts, the print > > statement inside the tick method is called right on cue every > > second. The print statement in drawRect, however, is never called, > > despite my self.display() line inside tick. > > I suggest invoking self.setNeedsDisplay_(True) before self.display(). > > Also, read the Cocoa drawing Guide available from > http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/CocoaDrawingGuide.pdf > > Ciao, > Bob > > > |
|
From: John B. <nho...@gm...> - 2008-04-01 07:58:32
|
Carl, Just FYI I copied your Lattice class into a new project and it all works fine as-is. So maybe there is something wrong with your nib setup - are you definitely calling the "start" action on the correct Lattice view (but presumably there's only one)? The difference between setNeedsDisplay: and display is that the former just marks the view as dirty and needing display (when the window is next redrawn). The latter draws the view immediately. Since you are only updating every 1 sec then calling either is fine, but using setNeedsDisplay: is more common. Regards, John ____________________ Dr. John Buckley nho...@gm... www.olivetoast.com Mac OS X Leopard ____________________ On 31 Mar 2008, at 23:55, Carl Bauer wrote: > Thanks guys. I have read the drawing guide, Bob. It was okay. I > guess I need to read the guide on Views as well before I ask any > more questions. Till then... > > -Carl > > On Mon, Mar 31, 2008 at 4:25 PM, Bob Vadnais <pyobjc- > de...@bo...> wrote: > On Mar 31, 2008, at 8:10 AM, Carl Bauer wrote: > > > Hey John, thanks for the reply. I implemented your changes, but the > > display is still not being refreshed. I put a print statement inside > > tick_(...) and drawRect_(...). When the timer starts, the print > > statement inside the tick method is called right on cue every > > second. The print statement in drawRect, however, is never called, > > despite my self.display() line inside tick. > > I suggest invoking self.setNeedsDisplay_(True) before self.display(). > > Also, read the Cocoa drawing Guide available from http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/CocoaDrawingGuide.pdf > > Ciao, > Bob > > > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace_______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev |
|
From: Carl B. <car...@gm...> - 2008-04-01 07:51:04
|
Well, now I'm confused. def isOpaque(self) is now in the class and returns
True (a key step, thanks David). I'm also using setNeedsDisplay_(True) and
displayIfNeeded() methods (thanks Bob). Still, drawRect is not called.
Here's the code:
class Lattice(NibClassBuilder.AutoBaseClass):
# the actual base class is NSView
color = NSColor.redColor()
toggle = 0
rect = NSMakeRect(40,40,40,40)
def drawRect_(self,frameRect):
print "drawRect called"
def isOpaque(self):
return True
def start_(self, sender):
self.timer=NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats
_(1.0,self,self.tick,None,True)
def tick(self,timer):
self.toggle = (self.toggle+1)%2
if self.toggle:
self.color = NSColor.blueColor()
else:
self.color = NSColor.redColor()
self.setNeedsDisplay_(True)
self.displayIfNeeded()
Google searches turned up a few comments about having to return control to
the runloop for anything to happen. Not sure I understand why that is, since
all the appledev docs tell me to just do exactly what I'm doing and the
runloop should be notified. I don't even know when I took control from the
runloop or how to give it back.
I will try some cocoa lists if no one knows what's going on here. Thanks
everyone.
-Carl
On Mon, Mar 31, 2008 at 4:55 PM, Carl Bauer <car...@gm...> wrote:
> Thanks guys. I have read the drawing guide, Bob. It was okay. I guess I
> need to read the guide on Views as well before I ask any more questions.
> Till then...
>
> -Carl
>
>
> On Mon, Mar 31, 2008 at 4:25 PM, Bob Vadnais <pyo...@bo...>
> wrote:
>
> > On Mar 31, 2008, at 8:10 AM, Carl Bauer wrote:
> >
> > > Hey John, thanks for the reply. I implemented your changes, but the
> > > display is still not being refreshed. I put a print statement inside
> > > tick_(...) and drawRect_(...). When the timer starts, the print
> > > statement inside the tick method is called right on cue every
> > > second. The print statement in drawRect, however, is never called,
> > > despite my self.display() line inside tick.
> >
> > I suggest invoking self.setNeedsDisplay_(True) before self.display().
> >
> > Also, read the Cocoa drawing Guide available from
> > http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/CocoaDrawingGuide.pdf
> >
> > Ciao,
> > Bob
> >
> >
> >
>
|
|
From: Jack J. <Jac...@cw...> - 2008-04-01 12:01:16
|
This starts to sound like a problem I have occasionally (in ObjC), which has to do with trying to do drawing in another thread. What works for me is using performSelectorOnMainThread to call setNeedsDisplay in the main thread. That usually does the trick. But, given the fact that you come from a timer, you may then want to completely get rid of the NSTimer and use iterative performSelector:withObject:afterDelay: to do everything in the main thread. On 1 apr 2008, at 09:51, Carl Bauer wrote: > Well, now I'm confused. def isOpaque(self) is now in the class and > returns True (a key step, thanks David). I'm also using > setNeedsDisplay_(True) and displayIfNeeded() methods (thanks Bob). > Still, drawRect is not called. Here's the code: > > class Lattice(NibClassBuilder.AutoBaseClass): > # the actual base class is NSView > color = NSColor.redColor() > toggle = 0 > rect = NSMakeRect(40,40,40,40) > > def drawRect_(self,frameRect): > print "drawRect called" > > def isOpaque(self): > return True > > def start_(self, sender): > > self > .timer > = > NSTimer > .scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_ > (1.0,self,self.tick,None,True) > > def tick(self,timer): > self.toggle = (self.toggle+1)%2 > if self.toggle: > self.color = NSColor.blueColor() > else: > self.color = NSColor.redColor() > self.setNeedsDisplay_(True) > self.displayIfNeeded() > > Google searches turned up a few comments about having to return > control to the runloop for anything to happen. Not sure I understand > why that is, since all the appledev docs tell me to just do exactly > what I'm doing and the runloop should be notified. I don't even know > when I took control from the runloop or how to give it back. > > I will try some cocoa lists if no one knows what's going on here. > Thanks everyone. > > -Carl > > On Mon, Mar 31, 2008 at 4:55 PM, Carl Bauer <car...@gm...> > wrote: > Thanks guys. I have read the drawing guide, Bob. It was okay. I > guess I need to read the guide on Views as well before I ask any > more questions. Till then... > > -Carl > > > On Mon, Mar 31, 2008 at 4:25 PM, Bob Vadnais <pyobjc- > de...@bo...> wrote: > On Mar 31, 2008, at 8:10 AM, Carl Bauer wrote: > > > Hey John, thanks for the reply. I implemented your changes, but the > > display is still not being refreshed. I put a print statement inside > > tick_(...) and drawRect_(...). When the timer starts, the print > > statement inside the tick method is called right on cue every > > second. The print statement in drawRect, however, is never called, > > despite my self.display() line inside tick. > > I suggest invoking self.setNeedsDisplay_(True) before self.display(). > > Also, read the Cocoa drawing Guide available from http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/CocoaDrawingGuide.pdf > > Ciao, > Bob > > > > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace_______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev -- Jack Jansen, <Jac...@cw...>, http://www.cwi.nl/~jack If I can't dance I don't want to be part of your revolution -- Emma Goldman |
|
From: Black <py...@bl...> - 2008-04-01 12:38:18
|
I'm coming to this thread a little late, but looking at your code, I
don't see where you have installed the timer into the run loop...
Here is an example taken from one of my apps:
self.timer =
NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_
(1/150., self, self.heartbeat, None, True)
NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer,
NSDefaultRunLoopMode) NSRunLoop.currentRunLoop
().addTimer_forMode_(self.timer, NSEventTrackingRunLoopMode)
On Mar 30, 2008, at 7:03 PM, Carl Bauer wrote:
> I'm a physics grad student (not a coder) wanting to put together a
> slick realtime physics simulation for my statistical mechanics
> class. (Simulating the 2D Ising model for ferromagnets in case
> anyone cares).
>
> Anyway, to start, I'm just trying to get a rectangle to change
> colors periodically. Why doesn't this work?
>
> import objc
> from Foundation import *
> from AppKit import *
> from PyObjCTools import NibClassBuilder, AppHelper
> from Quartz import NSColor
>
> NibClassBuilder.extractClasses("MainMenu")
>
> # class defined in MainMenu.nib
> class Lattice(NibClassBuilder.AutoBaseClass):
> # the actual base class is NSView
> color = NSColor.redColor()
> toggle = 0
> rect = NSMakeRect(40,40,40,40)
>
> def drawRect_(self,frameRect):
> NSEraseRect(self.rect)
> self.color.setFill()
> NSRectFill(self.rect)
>
> def start_(self, sender):
>
> self.timer=NSTimer.scheduledTimerWithTimeInterval_target_selector_user
> Info_repeats_(1.0,self,self.tick,None,True)
>
> def tick(self,timer):
> self.toggle = (self.toggle+1)%2
> if self.toggle:
> self.color = NSColor.blueColor()
> else:
> self.color = NSColor.redColor()
> self.display()
>
> if __name__ == "__main__":
> AppHelper.runEventLoop()
>
> The rectangle is drawn just fine at the beginning, but the timer
> doesn't seem to actually invoke drawRect_. I'm probably just not
> understanding how to properly use display()? Let me know if I'm
> being annoying and should just post to a different mailing list.
>
> Thanks,
> Carl
> ----------------------------------------------------------------------
> ---
> Check out the new SourceForge.net Marketplace.
> It's the best place to buy or sell services for
> just about anything Open Source.
> http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/
> marketplace_______________________________________________
> Pyobjc-dev mailing list
> Pyo...@li...
> https://lists.sourceforge.net/lists/listinfo/pyobjc-dev
|
|
From: Carl B. <car...@gm...> - 2008-04-01 17:10:53
|
Black,
the Cocoa doc tells me that NSTimer.scheduledTimerWithTimeInterval_...(...)
automatically adds the timer to the runloop for the NSDefaultRunLoopMode.
Maybe "NSEventTrackingRunLoopMode" is the key? I will try what you suggest
when I get home.
John--"Just FYI I copied your Lattice class into a new project and it all
works fine as-is."
hmmm. That's weird. I know I am calling the correct start method. There's
only one, and when I put a print statement inside tick_(), it gets called
every second immediately after I call start_(). I'll comb through my .nib
file when I get home. Maybe you could send me a copy of yours? or vice
versa.
On Tue, Apr 1, 2008 at 6:38 AM, Black <py...@bl...> wrote:
>
> I'm coming to this thread a little late, but looking at your code, I
> don't see where you have installed the timer into the run loop...
>
> Here is an example taken from one of my apps:
>
> self.timer =
> NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_
> (1/150., self, self.heartbeat, None, True)
> NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer,
> NSDefaultRunLoopMode) NSRunLoop.currentRunLoop
> ().addTimer_forMode_(self.timer, NSEventTrackingRunLoopMode)
>
> On Mar 30, 2008, at 7:03 PM, Carl Bauer wrote:
> > I'm a physics grad student (not a coder) wanting to put together a
> > slick realtime physics simulation for my statistical mechanics
> > class. (Simulating the 2D Ising model for ferromagnets in case
> > anyone cares).
> >
> > Anyway, to start, I'm just trying to get a rectangle to change
> > colors periodically. Why doesn't this work?
> >
> > import objc
> > from Foundation import *
> > from AppKit import *
> > from PyObjCTools import NibClassBuilder, AppHelper
> > from Quartz import NSColor
> >
> > NibClassBuilder.extractClasses("MainMenu")
> >
> > # class defined in MainMenu.nib
> > class Lattice(NibClassBuilder.AutoBaseClass):
> > # the actual base class is NSView
> > color = NSColor.redColor()
> > toggle = 0
> > rect = NSMakeRect(40,40,40,40)
> >
> > def drawRect_(self,frameRect):
> > NSEraseRect(self.rect)
> > self.color.setFill()
> > NSRectFill(self.rect)
> >
> > def start_(self, sender):
> >
> > self.timer=NSTimer.scheduledTimerWithTimeInterval_target_selector_user
> > Info_repeats_(1.0,self,self.tick,None,True)
> >
> > def tick(self,timer):
> > self.toggle = (self.toggle+1)%2
> > if self.toggle:
> > self.color = NSColor.blueColor()
> > else:
> > self.color = NSColor.redColor()
> > self.display()
> >
> > if __name__ == "__main__":
> > AppHelper.runEventLoop()
> >
> > The rectangle is drawn just fine at the beginning, but the timer
> > doesn't seem to actually invoke drawRect_. I'm probably just not
> > understanding how to properly use display()? Let me know if I'm
> > being annoying and should just post to a different mailing list.
> >
> > Thanks,
> > Carl
> > ----------------------------------------------------------------------
> > ---
> > Check out the new SourceForge.net Marketplace.
> > It's the best place to buy or sell services for
> > just about anything Open Source.
> > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/
> > marketplace_______________________________________________
> > Pyobjc-dev mailing list
> > Pyo...@li...
> > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev
>
>
|
|
From: John B. <nho...@go...> - 2008-03-31 09:45:34
|
Hi Carl,
You don't pass in the function object when specifying Objective-C
methods, but a method "selector", which in Python land is just a
string (in Objective-C selectors have the type SEL, which may or may
not also be a string). Be careful to fully specify the selector by
including the colon for each argument e.g.
NSTimer
.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_
(1.0,self,'tick:',None,True)
Note that in the Python method definition the colon is replaced by an
underscore. So in Objective-C your 'tick' method would look like:
- (void)tick:(NSTimer*)timer
{
// Implemenation here
}
In Python this must be translated to:
def tick_(self, timer):
# implementation here
However the "selector" string must always use the Objective-C version
i.e. with the colon.
Regards,
John
____________________
Dr. John Buckley
nho...@gm...
www.olivetoast.com
Mac OS X Leopard
____________________
On 31 Mar 2008, at 00:03, Carl Bauer wrote:
> I'm a physics grad student (not a coder) wanting to put together a
> slick realtime physics simulation for my statistical mechanics
> class. (Simulating the 2D Ising model for ferromagnets in case
> anyone cares).
>
> Anyway, to start, I'm just trying to get a rectangle to change
> colors periodically. Why doesn't this work?
>
> import objc
> from Foundation import *
> from AppKit import *
> from PyObjCTools import NibClassBuilder, AppHelper
> from Quartz import NSColor
>
> NibClassBuilder.extractClasses("MainMenu")
>
> # class defined in MainMenu.nib
> class Lattice(NibClassBuilder.AutoBaseClass):
> # the actual base class is NSView
> color = NSColor.redColor()
> toggle = 0
> rect = NSMakeRect(40,40,40,40)
>
> def drawRect_(self,frameRect):
> NSEraseRect(self.rect)
> self.color.setFill()
> NSRectFill(self.rect)
>
> def start_(self, sender):
>
> self
> .timer
> =
> NSTimer
> .scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_
> (1.0,self,self.tick,None,True)
>
> def tick(self,timer):
> self.toggle = (self.toggle+1)%2
> if self.toggle:
> self.color = NSColor.blueColor()
> else:
> self.color = NSColor.redColor()
> self.display()
>
> if __name__ == "__main__":
> AppHelper.runEventLoop()
>
> The rectangle is drawn just fine at the beginning, but the timer
> doesn't seem to actually invoke drawRect_. I'm probably just not
> understanding how to properly use display()? Let me know if I'm
> being annoying and should just post to a different mailing list.
>
> Thanks,
> Carl
> -------------------------------------------------------------------------
> Check out the new SourceForge.net Marketplace.
> It's the best place to buy or sell services for
> just about anything Open Source.
> http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace_______________________________________________
> Pyobjc-dev mailing list
> Pyo...@li...
> https://lists.sourceforge.net/lists/listinfo/pyobjc-dev
|