paint中的Graphics从何而来?

原创 2007年10月10日 13:41:00

Canvas中调用repaint后,系统会调用paint(Graphics g),而能给与程序员发挥的空间就在paint里,那么,paintGraphics从那里来的呢?换句话说,我们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);//targetNULL

        }

    }

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(); //猜测可能是KVMDEVICE的桥接器

        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的底层实现,也就是nativeinit(),会把这个Graphics给对接到某个具体的平台,比如win32GDISymbianGraphics GDI,还有LINUX常见的QT平台的GDI等等。

最后还望各位看官给多多指点错误。我去喝咖啡去了。。。

java画图总结之三(常用方法paint,repaint,update)

三,常用方法paint,repaint,update 这个问题的由来是因为,我在编写java小程序,画图的时候,发现我重写了paint(graphics g)方法,而执行的时候调用的是repaint(...
  • tanjun592
  • tanjun592
  • 2017年02月08日 13:56
  • 5200

Java中repaint方法清除原来图像问题

虽然Java界面编程作用不大,但在兴趣的驱使下还是了解了一下,在写小程序的时候发现了repaint方法有时候会清理原来的图像,有时候又不清理。下面贴出我通过API文档得出的结论。 程序作用:每点击一次...
  • qq_26738489
  • qq_26738489
  • 2016年08月14日 00:50
  • 3674

使用paint画图应加上super.paint(g)

paint(g)函数会重绘图像,要加上super.paint(g),表示在原来图像的基础上,再画图。如果不加super.paint(g),重绘时,会将原有的绘制清空,再根据paing(g)函数绘制。 ...
  • piaopiaopiaopiaopiao
  • piaopiaopiaopiaopiao
  • 2013年11月22日 09:49
  • 3524

一夫一妻制从何而来——人类私生活的演化

男婚女嫁,天经地义,古代男女之事,父母就能完全决定,“父母之命,媒妁之言”,甚至指腹为婚。如今呢,结婚成了年轻人的心头之痛,造就了一大批剩男剩女。自由恋爱的年代,为何婚姻变得如此艰难。想知道婚姻何去何...
  • booirror
  • booirror
  • 2016年05月08日 00:49
  • 831

深入分析Linux内核源码-第五章进程调度(时间片从何而来,如何分配给进程,讲解详细)

深入分析Linux内核源码-第五章进程调度【摘要】本章介绍了Linux系统的时间机制,包括系统时钟和硬件时钟之间的关系、各种时间标准的转换、时钟中断tick的维护;接着介绍了进程调度的几种常见算法、何...
  • rein07
  • rein07
  • 2011年06月09日 19:01
  • 6552

Android_ics_stagefright框架数据流向分析——1,待解码的原始数据从何而来

先明确一点,stagefright框架是典型的事件驱动型,数据的流向也受到事件驱动(driven by event)的影响,在awesomePlayer中主要的驱动事件有:onPrepareAsy...
  • sadamoo
  • sadamoo
  • 2013年09月21日 21:25
  • 764

第1.5节 无穷小从何而来?

   在今年十月份,国内新入学的大学生将会收到J.Keisler的一份礼物。这份礼物是什么呢?礼物珍贵吗?当然,十分珍贵。为什么?          在J.Keisler的《基础微积...
  • yuanmeng001
  • yuanmeng001
  • 2013年06月28日 05:23
  • 987

Linux(发行版)从何而来?

    初看起来,提出这个问题似乎很傻,实则不然。为什么?             大家知道,Linux内核的故事已经是老生长谈了。现在,Linux内核多半借助各式各样的所谓“发行版...
  • yuanmeng001
  • yuanmeng001
  • 2011年12月20日 04:53
  • 2109

浮动从何而来 我们为何要清除浮动 清除浮动的原理是什么

浮动(float),一个我们即爱又恨的属性。爱,因为通过浮动,我们能很方便地布局; 恨,浮动之后遗留下来太多的问题需要解决,特别是IE6-7以下无特殊说明均指 windows 平台的 IE浏览器 ...
  • Dohaelis
  • Dohaelis
  • 2016年09月01日 21:49
  • 140

兴趣从何而来?

做事情有三种境界:第一种境界是强迫,在外界(例如纪律)或者自己的强迫(自制力)下做事情,例如大部分人记英语单词,这种境界可以说是“苦不堪言”。第二种境界是习惯,做的过程中既没有痛苦也没有快乐,例如每天...
  • b5w2p0
  • b5w2p0
  • 2013年10月24日 14:58
  • 670
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:paint中的Graphics从何而来?
举报原因:
原因补充:

(最多只允许输入30个字)