JComponent repaint nightmare

Discussion in 'Java' started by Roger Davis, Nov 22, 2003.

  1. Roger Davis

    Roger Davis Guest

    I am trying to draw a complicated image into an on-screen window
    and make frequent, minor changes to that image, usually in
    response to user input, e.g., draw a rubberband bounding box, etc.
    I want to make these changes without having to completely
    redraw the image , i.e., I want to redraw only the small part
    of the image which has changed. Unfortunately every approach
    I have tried results in failure -- when I try to redraw some
    small part of my image, the unchanged (and un-redrawn) portion
    of the image disappears from the display. I have been
    stumbling lost through repaint() hell for three days now with
    no end in sight, and am hoping that someone out there can
    tell me how to do this. I am using Java 2 SE 1.4.2.

    I am an X11 programmer who is new to Java, so I may be going
    about this completely wrong, but here is what I am doing (based
    largely on suggestions from various Java books). My drawing
    object, called a Drawable, is an instantiation of my own direct
    subclass of JComponent. This Drawable object is encapsulated in a
    JScrollPane which has been stuffed into the content pane of a JFrame,
    which also has a JMenuBar. I am doing my drawing into an off-screen
    BufferedImage which I have allocated myself. Every time I perform
    a drawing operation on this BufferedImage, e.g., adjusting a rubberband
    bounding box, I create a Rectangle which bounds the affected area and
    place it onto a queue, and call the JComponent.repaint() method. I
    have overridden the JComponent.paint() method in my Drawable
    class to examine this queue and transfer the appropriate subsections
    of the BufferedImage into the Drawable. When my program starts
    and creates the initial large, complicated image and transfers the
    whole thing into the Drawable this works fine. What does *not*
    work is when I subsequently redraw some small piece of the image
    and then call repaint(), which forces a call to paint() -- when this
    happens the entire contents of the on-screen Drawable are wiped out,
    and all I see is my small updated area. Some agent external to my
    Drawable's paint() method is clearing the Drawable before that
    paint() method is called.

    I tried overriding JComponent's update() method as suggested in
    various books, but then found out that Swing does not even call
    JComponent.update(), which I confirmed empirically by putting print
    statements in my own overriding Drawable.update() method.

    I then discovered documentation in various places which mention some
    sneaky ComponentUI.update() method which may be clearing my JComponent.
    However, Sun's Javadoc says that this should happen only if the
    JComponent is opaque, and mine is not (at least according to isOpaque()
    at the time of creation of the JComponent -- I have not explicitly set
    it either way). Also, I've found other documentation that implies
    that this does not happen anyway if you are working with your own
    direct subclass of JComponent and have not explicitly created your
    own UI delegate. (I *am* using my own direct subclass of JComponent and
    I have *not* explicitly created any UI delegate. I don't even have a
    clue of what a UI delegate is.)

    After all of the above failed to get me anywhere, I scrapped the whole
    BufferedImage approach and tried to use Swing's own double-buffering.
    I have no idea if this is even possible and was not able to find any
    programming examples, so I may have gone about it completely wrong,
    but the bottom line is that failed also. I did a setDoubleBuffered()
    on my JComponent and did all of my draws to the JComponent, then called
    repaint(rect) after each drawing operation, where rect is the smallest
    bounding Rectangle that contained the affected area. I did not override
    JComponent.paint() in this attempt. This basically did the
    same thing as my BufferedImage approach, only with a lot more flicker.

    There has *got* to be a way to do this. I hope someone out there can
    tell me how!

    Thanks.

    --
    Roger Davis
    University of Hawaii/SOEST
     
    Roger Davis, Nov 22, 2003
    #1
    1. Advertising

  2. Roger Davis

    Harald Hein Guest

    "Roger Davis" wrote:

    > I am an X11 programmer who is new to Java,


    Then I would ugently suggest that you get the Painting article from sun
    and read it a few times.

    http://java.sun.com/products/jfc/tsc/articles/painting/index.html

    Then I would suggest to continue with

    http://java.sun.com/docs/books/tutorial/uiswing/14painting/index.html

    and

    http://java.sun.com/docs/books/tutorial/2d/index.html

    > largely on suggestions from various Java books).


    It doesn't sound as if these books are too great.

    > I am doing my drawing into an
    > off-screen BufferedImage which I have allocated myself.


    If you are only doing this for double buffering, this is not necessary.
    Swing does double-buffering by itself. Consider changing your algorithm
    so you don't need to buffer yourself. If you buffer yourself, turn at
    least Swing's double-buffering off.

    > I perform a drawing operation on this BufferedImage, e.g.,
    > adjusting a rubberband bounding box,


    Rubberbands etc. are maybe the only things where I would consider using
    paintImmediately, instead of going through the repaint/update/paint
    mechanism.

    > I create a Rectangle which
    > bounds the affected area and place it onto a queue,


    Which queue? You just claimed you use a BufferedImage. Please post
    complete, small example code. Code that can be compiled and runs as-is.

    > and call the
    > JComponent.repaint() method. I have overridden the
    > JComponent.paint()


    Override paintComponent(), not paint(). See the mentioned Painting
    article.

    > when
    > this happens the entire contents of the on-screen Drawable are
    > wiped out, and all I see is my small updated area.


    Use a debugger. Pay special attention to what is going on in the
    Superclass. You do call super.paint[Component](), don't you? You know
    that the clip rectangle and origin can be different in calls to
    paint[Component]()? Also use the debugger to check if and how much you
    copy from your BufferedImage to the Graphics object. Again, check the
    mentioned article.

    > Some agent
    > external to my Drawable's paint() method is clearing the Drawable
    > before that paint() method is called.


    There are no such agents. Yet again, learn more about the Swing/AWT
    painting mechanism.

    > I tried overriding JComponent's update() method as suggested in
    > various books,


    This is bullshit, because, as you have found out:

    > Swing does not even call
    > JComponent.update(), which I confirmed empirically by putting
    > print statements in my own overriding Drawable.update() method.


    You wouldn' have to, if you would have read the ...

    Throw that book away.

    > I then discovered documentation in various places which mention
    > some sneaky ComponentUI.update() method which may be clearing my
    > JComponent.


    ComponentUI.update() is only called by the paintComponent() method, if
    (a) there is a ui delegate, and (b) opaque is true.

    JPanes has a ui delegate, and yes, it fills (not cleans) the background
    with the background color, if opaque is true. JComponent doesn't have
    one. opaque is all about filling.

    If you overrider paintComponent(), you can decide for yourself what to
    do. If your superclass has a ui delegate, you can use it by just
    calling super.paintComponent() first in the method. If you don't have a
    ui delegate, you better make sure that you satisfy the opaque flag
    yourself.

    However, since, you are buffering your own image, you can satisfy the
    opaque flag by always at least copying as much data to the screen as
    indicated via the clip region (now you know why I suggested to use a
    debugger and check what's going on in the superclass and how the clip
    region is set).

    > I don't even have a clue of what a UI
    > delegate is.)


    Then get your ass up, and read about it.

    > I did a setDoubleBuffered()


    It is on by default.

    > on my JComponent and did all of
    > my draws to the JComponent,


    Using getGraphics()? This will never work.

    > There has *got* to be a way to do this. I hope someone out there
    > can tell me how!


    Stop whining, and start learning about the paint mechanism and how to
    use a debugger.
     
    Harald Hein, Nov 22, 2003
    #2
    1. Advertising

  3. Roger Davis

    Alex Hunsley Guest

    Roger Davis wrote:
    [snip]
    > I then discovered documentation in various places which mention some
    > sneaky ComponentUI.update() method which may be clearing my JComponent.
    > However, Sun's Javadoc says that this should happen only if the
    > JComponent is opaque, and mine is not (at least according to isOpaque()
    > at the time of creation of the JComponent -- I have not explicitly set
    > it either way). Also, I've found other documentation that implies
    > that this does not happen anyway if you are working with your own
    > direct subclass of JComponent and have not explicitly created your
    > own UI delegate. (I *am* using my own direct subclass of JComponent and
    > I have *not* explicitly created any UI delegate. I don't even have a
    > clue of what a UI delegate is.)


    For starters, you should be doing your own painting in paintComponent,
    and not paint (if that's what you're doing).
    The update method, which you should leave well alone, calls paint, which
    you should also leave well alone.
    Paint calls paintComponent, paintBorder, and paintChildren. Hence, if
    you override paintComponent in the right way, you should be ok.

    If you don't call super.paintComponent(..) in your own paintComponent
    method, swing won't do it's default blanking of the drawing area, which
    is what it sounds like is happening.
    You might also be interested in looking at Graphics.setClip if you want
    to clip what gets drawn to a specific region.

    I'm getting around, at last, to doing a web page about this very subject
    (painting in swing + double buffering), I really need to finish it as it
    sounds like it would be of help in your situation!


    > After all of the above failed to get me anywhere, I scrapped the whole
    > BufferedImage approach and tried to use Swing's own double-buffering.
    > I have no idea if this is even possible and was not able to find any
    > programming examples, so I may have gone about it completely wrong,
    > but the bottom line is that failed also. I did a setDoubleBuffered()
    > on my JComponent and did all of my draws to the JComponent, then called
    > repaint(rect) after each drawing operation, where rect is the smallest
    > bounding Rectangle that contained the affected area. I did not override
    > JComponent.paint() in this attempt. This basically did the
    > same thing as my BufferedImage approach, only with a lot more flicker.
    >
    > There has *got* to be a way to do this. I hope someone out there can
    > tell me how!


    Don't draw individual bits and then call repaint() after each bit. As
    long as you override paintComponent, you can control what gets painted.
    Call repaint() when you want to force paintComponent to get called.

    I think doing your own double buffering sounds ideal in this situation.
     
    Alex Hunsley, Dec 11, 2003
    #3
  4. Roger Davis

    Alex Hunsley Guest

    Roger Davis wrote:

    > I am trying to draw a complicated image into an on-screen window
    > and make frequent, minor changes to that image, usually in

    [snip]

    P.S. posting code would help a lot. If not to the group, to me, at
    (remove the tooth from the email address to
    get correct address).
     
    Alex Hunsley, Dec 11, 2003
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Richard B. Christ

    Retarding the repainting of a JComponent

    Richard B. Christ, Oct 24, 2003, in forum: Java
    Replies:
    1
    Views:
    321
    Harald Hein
    Oct 25, 2003
  2. dbritton

    How to "ghost" a jcomponent?

    dbritton, Feb 5, 2004, in forum: Java
    Replies:
    2
    Views:
    302
    Andrew Thompson
    Feb 5, 2004
  3. smat

    JComponent on JTree

    smat, Oct 24, 2005, in forum: Java
    Replies:
    2
    Views:
    1,494
    Roedy Green
    Oct 25, 2005
  4. Jacob
    Replies:
    8
    Views:
    574
    VisionSet
    Mar 18, 2006
  5. zerg
    Replies:
    125
    Views:
    2,666
Loading...

Share This Page