首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 第二书店 程序员
您的位置:Mobile->paint中的Graphics从何而来

paint中的Graphics从何而来2007-10-11 来自:lizhe1985  [收藏到我的网摘]

来源:Crazyerghb的专栏 - CSDNBlog

  Canvas中调用repaint后,系统会调用paint(Graphics g),而能给与程序员发挥的空间就在paint里,那么,paint的Graphics从那里来的呢?换句话说,我们paint操作的东西到底是什么呢?他又是怎么反应到手机硬件屏幕上了呢?

  1。我们先来看看repaint是怎么实现的。

public final void repaint(int x, int y, int width, int height) {

synchronized (Display.LCDUILock) {

callRepaint(x + viewport[X], y + viewport[Y], width, height, null);

}

}

  2。那么callReapint是怎么实现的呢?

  在Displable里有一个方法(以final标识),此方法禁止任何子类重写,就是为了保证只有他来控制repaint事件的传递:

final void callRepaint(int x, int y, int width, int height, Object target) {

if (currentDisplay != null) {

// Note: Display will not let anyone but the current

// Displayable schedule repaints

currentDisplay.repaintImpl(paintDelegate, x, y, width, height, target); //target是NULL

}

}

  3,在Diaplay里,此方法的实现如下:

void repaintImpl(Displayable d, int x, int y, int w, int h,

Object target) {



synchronized (LCDUILock) {

if (paintSuspended || !hasForeground || d != current) {

return;

}

}



eventHandler.scheduleRepaint(x, y, w, h, target); //把Repaint的请求部署下去

}

  4.

/**

* Called to schedule a repaint of the current Displayable

* as soon as possible

*

* @param x The x coordinate of the origin of the repaint rectangle

* @param y The y coordinate of the origin of the repaint rectangle

* @param w The width of the repaint rectangle

* @param h The height of the repaint rectangle

* @param target An optional target Object, which may have been the

* original requestor for the repaint

*/

public void scheduleRepaint(int x, int y, int w, int h, Object target) {

eventQueue.push(x, y, w, h, target); //安排后的处理就是往事件队列里push一个消息

}

  5.

/**

* Push a repaint

*

* @param x The x origin coordinate

* @param y The y origin coordinate

* @param w The width

* @param h The height

* @param target The optional paint target

*/

public void push(int x, int y, int w, int h, Object target) {



try {

w += x; // convert from width, height to absolute

h += y; // x2, y2

if (x < 0) x = 0;

if (y < 0) y = 0;



synchronized (qLock) {

if (paintX1 == -1) {

// If we have no pending repaint

// just store the region

paintX1 = x;

paintY1 = y;

paintX2 = w;

paintY2 = h;

paintTarget = target;

} else {

// If there is a pending repaint

// union the dirty regions

if (paintX1 > x) {

paintX1 = x;

}

if (paintY1 > y) {

paintY1 = y;

}

if (paintX2 < w) {

paintX2 = w;

}

if (paintY2 < h) {

paintY2 = h;

}

paintTarget = null;

}

} // synchronized

} catch (Throwable t) {

t.printStackTrace();

}

queuedEventHandler.process(); //push消息后,就要立即进行处理,

}

  6. 其实,一个事件队列就是一个无限循环的线程,不停的检查队列,看是否有需要处理的消息,有则处理,无则等待。现在既然已经push进去一个消息,就要立即唤醒他去处理这个消息。所以自然就notify了。

/**

* Signal this handler there is a need to process

* a pending event.

*/

public synchronized void process() {

try {

notify();

} catch (Throwable t) {

// TO DO: Do something more useful with this

t.printStackTrace();

}

}

  7. 我们来看看事件队列EventQuene的线程是如何定义的,其中repaintScreenEvent是来对repaint事件进行处理的。

/**

* Process events from the EventQueue

*/

public void run() {

int x1, y1, x2, y2, type = 0;

Display parentOfNextScreen = null;

Displayable nextScreen = null;

boolean call = false;



........

if (x1 != -1) {

repaintScreenEvent(x1, y1, x2, y2, target);

x1 = y1 = x2 = y2 = -1;

target = null;

}

  8. 那么,我们再来看看是如何实现repaintScreenEvent的,

/**

* Process a repaint event

*

* @param x1 The x origin coordinate

* @param y1 The y origin coordinate

* @param x2 The lower right x coordinate

* @param y2 The lower right y coordinate

* @param target The optional paint target

*/

void repaintScreenEvent(int x1, int y1, int x2, int y2, Object target) {

try {

synchronized (eventLock) {

displayManager.repaint(x1, y1, x2, y2, target); //调用了屏幕管理器的reapint,请注意,这是5个参数的repaint

}

} catch (Throwable t) {

handleThrowable(t);

}

}

  9. 这个5个参数的实现方法如下:

/*

* SYNC NOTE: this method performs its own locking of

* LCDUILock and calloutLock. Therefore, callers

* must not hold any locks when they call this method.

*/

void repaint(int x1, int y1, int x2, int y2, Object target) {

Displayable currentCopy = null;



synchronized (LCDUILock) {

if (paintSuspended || !hasForeground) {

return;

}

currentCopy = current;

}



if (currentCopy == null) {

return;

}



screenGraphics.reset(x1, y1, x2, y2);

current.callPaint(screenGraphics, target);

refresh(x1, y1, x2, y2);

}

  10. 可见,screenGraphcis当作了参数传递给了callPaint,在需要知道screenGraphics如何来的之前,我们先看看callPaint方法。

/**

* Paint this Canvas

*

* @param g the Graphics to paint to

* @param target the target Object of this repaint

*/

void callPaint(Graphics g, Object target) {

super.callPaint(g, target);



if (g.getClipY() + g.getClipHeight() <= viewport[Y]) {

return;

}



// We prevent the Canvas from drawing outside of the

// allowable viewport - such as over the command labels

g.clipRect(viewport[X], viewport[Y],

viewport[WIDTH],

viewport[HEIGHT]);



synchronized (Display.calloutLock) {

g.translate(viewport[X], viewport[Y]);

try {

paint(g); //这就是调用后repaint方法后,系统会调用到paint(g),这个g就是调用callPaint方法传递过来的screenGraphcis,请看下面分析

} catch (Throwable t) {

Display.handleThrowable(t);

}

g.translate(-viewport[X], -viewport[Y]);

}

}

  11,现在我们来看看screenGraphics是从那里来的,在Display类里,有一段静态数据初始化的代码

./*

* ************* Static initializer, constructor

*/

static {



/* done this way because native access to static fields is hard */

DeviceCaps c = new DeviceCaps();



WIDTH = c.width;

HEIGHT = c.height;

ADORNEDHEIGHT = c.adornedHeight;

………



c = null; // let the DeviceCaps instance be garbage collected



/* Let com.sun.midp classes call in to this class. */

displayManagerImpl = new DisplayManagerImpl(); //初始化屏幕管理器

DisplayManagerFactory.SetDisplayManagerImpl(displayManagerImpl); //得到屏幕管理器,这个一个工厂方法,为以后使用做准备,此处不赘叙

deviceAccess = new DisplayDeviceAccess(); //猜测可能是KVM和DEVICE的桥接器

eventHandler = getEventHandler(); //事件处理器



screenGraphics = Graphics.getGraphics(null); //哈哈,screenGraphics找到了

}



  12. 在Graphics类里有个方法,getGraphics,但是,这个方法是默认的package级别的访问权限。所以我们不会看到。

static Graphics getGraphics(Image img) {

if (img == null) {

return new Graphics(Display.WIDTH, Display.HEIGHT);

} else {

return new ImageGraphics(img); //猜猜它是为谁服务的?

}

}

  13. Graphics的构造方法如下:

Graphics(int w, int h) {

destination = null;



maxWidth = (short) (w & 0x7fff);

maxHeight = (short) (h & 0x7fff);



init();

reset();

}

  14. 天哪,终于找到了,native的一个接口,init,是它来初始化了Graphics

/**

* Intialize the native peer of this Graphics context

*/

private native void init();

  15.其实,找到这里,还不能说挖掘到了最根本的实现,但是,我们暂且就挖到这里,所以,总结一下,paint中的Graphics,其实是Display来提供的,只是,这个变量不会让我们看到。那么KVM的底层实现,也就是native的init(),会把这个Graphics给对接到某个具体的平台,比如win32的GDI,Symbian的Graphics GDI,还有LINUX常见的QT平台的GDI等等。

推荐人评论

Canvas中调用repaint后,系统会调用paint(Graphics g),而能给与程序员发挥的空间就在paint里,那么,paint的Graphics从那里来的呢?换句话说,paint操作的东西到底是什么呢?他又是怎么反应到手机硬件屏幕上了呢?

用户评论

正在载入评论列表...

是谁推荐了此篇文章

专家头像李哲
个人blog发送信息
李哲推荐的其他文章

赞助商精华文章

热点新闻

热点评论

    精彩视频

    精彩专题

    网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|版权声明|问题报告

    北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright 2000-2008, CSDN.NET, All Rights Reserved
    GongshangLogo