MIDP Canvas Repainting

The low-level user-interface APIs of the Mobile Information Device Profile (MIDP) allow you to control exactly what is drawn on the screen through the Canvas class. Sometimes, though, you also want to have control over when the drawing occurs, or to be notified when the drawing is complete. Before exploring either topic, I should recap how canvas painting works in a general sense.

Generally, it is the device that controls when painting occurs. A painting event is triggered when any of a number of things occur -- the canvas is shown for the first time, a menu that was hiding part of the canvas is withdrawn, or an alert is dismissed. The device then invokes the canvas's paint method, passing it a Graphics object initialized to draw on the correct parts of the display. The method does the drawing and returns as quickly as possible. Note that no key or pointer events are processed while the painting occurs -- execution of events, including repaint notifications, is always serialized.

The simplest way to handle repaints is to let the system schedule them. All you do is tell the system that the canvas needs repainting by calling the Canvas.repaint() method:

Canvas c = ...

c.repaint( 20, 20, 50, 50 ); // x, y, w, h

The system queues a paint request for the given area. (Another version of the repaint method takes no arguments and queues a paint request for the entire canvas.) If you mark two or more areas for repainting within a short span of time, the system may combine the paint requests into a single request to paint the union of the two areas (the smallest rectangle containing both). At some point the system invokes the canvas's paint method, passing it a Graphics object whose clipping area is set to the area that needs repainting.

You can call the repaint method from any thread, because the MIDP user-interface classes are all thread-safe, unlike the J2SE Swing classes you may already be familiar with.

Sometimes, though, waiting for the system to call the paint method is not good enough. Perhaps you want to update the display immediately in response to some user input. You can force an update to occur at any point by calling the serviceRepaints() method:

Canvas c = .....

c.repaint( 0, 0, 20, 30 );
c.serviceRepaints(); // paint it now

If the canvas is visible and one or more paint requests are queued, serviceRepaints() causes the system to invoke the canvas's paint method as soon as possible. serviceRepaints() does not return until the paint method returns.

Note that you have no way to control -- or even know -- which thread the system uses when it invokes the canvas's paint method. Often, it uses the same thread that called serviceRepaints(). The system may choose to use a different thread, however, and block the initiating thread until the painting is finished. A deadlock can occur if the paint method requires access to an object that the initiating thread has locked. You must therefore be careful about accessing synchronized objects in your paint() method.

What if you want to execute some code after the display is repainted? Calling the code from the canvas's paint method may not work as you expect it -- the display may be updated only after the paint method returns, especially if the system does automatic double-buffering for flicker-free output. A better tactic is to use the Display.callSerially() method, passing it an object that implements the standard java.lang.Runnable interface:

Runnable r = ....
Display d = ....

d.callSerially( r );

Each callSerially() invocation adds the given object to a system-maintained list. As it processes events, the system removes an object from the list and invokes its run method, effectively serializing the call with system-generated events. Furthermore, if a repaint is pending when the object is added to the list, its run method is not invoked until after the display has been repainted -- this order is guaranteed by the MIDP specification. You can use this feature to animate images, as in this example adapted from the MIDP specification:

public class Animation extends Canvas implements Runnable {
    private Image[] frames;
    private int     next = 0;
    private boolean go = false;

    public Animation( Image[] frames ){
	this.frames = frames;
    }

    protected void paint( Graphics g ){
	g.drawImage( frames[next], 0, 0, g.TOP | g.LEFT );
    }

    public void startAnimation(){
	go = true;
	repaint();
	callSerially( this );
    }

    public void stopAnimation(){
    go = false;
    }

    public void run() { // called after previous repaint is
    finished
    if( go ){
	if( ++next >= frames.length ) next = 0;
	repaint();
	callSerially( this );
	}
    }    
}

One problem with this approach to animation, however, is that the animation rate -- the number of frames painted per second -- is device-dependent. It may be better to use a timer-based approach.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值