Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

JScrollPane: Unnecessary Full Repaints

 
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've got a large scrollable view tied to a minature view, where if you drag the mouse around the minature view, the large view scrolls as well to match it. If anybody has Paint Shop Pro 8, it's much like the Preview pane. For maximum rendering speed when scrolling, I call the scroll pane viewport's scrollRectToVisible() method when adjusting the viewport position. When dragging perfectly horizontally or vertically against the edges of the miniature view, the speed is excellent and only partial repaints are occurring. However, when dragging diagonally or erratically (in increments smaller than the viewable area), lots of full repaints are triggering and I can visibly see the large view refreshes slow down as a result. Is there any way to avoid these full repaints?

As I understand it, ultimately the speed scrollRectToVisible() offers is due to calls to Graphics.copyArea() which can quickly "shift" the center(ish) region of what has already been painted in an appropriate direction, after which the viewed component's paint() method is called, with a clipping region that constitutes what areas of the viewed component have just scrolled into the viewport. I've done a few tests using copyArea() for "infinite scrolling" of a pattern, and it seems to behave exactly as I would expect it to for diagonals. That being the case, I don't understand why I'm getting these full repaints when scrolling diagonally in relatively small increments with scrollRectToVisible().

Any help is appreciated!
 
Charles Rector
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I was able to roll my own solution. It took a little while, but it was educational at least. Having dug through all the machinery behind JViewport, I'm just about convinced rolling my own is a better solution for my particular case. The diagonal scrolling is now just as quick as vertical and horizontal scrolling, but it's a little bit faster overall as well.

I'm still baffled as to why JViewport is triggering those full repaints when scrolling diagonally. Slower or not, just using a JScrollPane would've been less work than writing my own! If anybody is good and familiar with JViewport's refresh mechanics, I'd be very interested to know what the deal is!
 
Charles Rector
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
After digging around even further, I found the actual reason why diagonal scrolling causes full repaints. JViewport's paint() method only takes into account one rectangle when drawing the newly exposed area. Its computeBlit() method returns false for diagonal scrolls, which means "cannot do a partial blit" and a full repaint is triggered. On the bright side, I may be able to override some methods to get diagonal scrolling working. On the not so bright side, I might have to override a lot of methods. Ah well!
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A search in the bug database shows that this is a long known bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4486696

Unfortunately, it isn't even evaluated by Sun... :roll:
 
Ranch Hand
Posts: 15304
6
Mac OS X IntelliJ IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm just impressed that you were able to dig deep enough and understand enough to figure out the problem and create a solution for yourself. Very nice work. I'm jealous.
 
Charles Rector
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Wow, so someone else has actually run into this problem. Many thanks for the link, Ilja! Gregg, I'm surprised I was able to myself, to tell the truth. I give all the credit to stubbornness.

Reading the bug listing was a hoot. They mention subclassing JViewport is not easy, and let me tell you: it ain't. However! I am just *this* close to having a subclassed JViewport that scrolls diagonally quickly. I basically copied the entire JViewport source, then tossed as many methods as possible, leaving only paint(), windowBlitPaint(), and a bunch of other private support crap.

It scrolls great so far, except for some artifacts trailing from the corners (all except the lower right, for some reason). As soon as I have a working version I'll link to it, for anybody that's interested.
 
Charles Rector
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Got this puppy figured out! Efficient diagonal scrolling baby!

Here's a link: CustomViewport.java

Primarily of interest are the computeBlit(), computeBlitRects(), windowBlitPaint() and blitDoubleBuffered() methods. I didn't pay too much attention to any of the other methods. I don't think blitDoubleBuffered() is tied to setDoubleBuffered(), but I could be wrong. I think regardless of the scroll method, it always tries to use a VolatileImage back buffer so that all your rendering isn't taking place directly on visible video memory (slooow).

The key modification was arranging everything so that blitDoubleBuffered() could refresh more than one rectangle (well, 2 basically) when scrolling diagonally, ie. the L-shape area which just scrolled into view. To compute the refresh rectangles, I added the computeBlitRects() method. I also modified the computeBlit() method so that it would return true when a diagonal scroll was detected. The computeBlitRects() method is called when a scroll is detected in windowBlitPaint(), and I modified the parameter list for blitDoubleBuffered() to accept an array of rectangles rather than a single rectangle (the clip arguments.) A few dozen tweaks to blitDoubleBuffered() and computeBlitRects() later, I finally broke down and reasoned out what I was doing and then it was all good. ;-)

I tossed in some comments here and there where I thought they might do some good. But I figure anybody with a reason to use this class probably already has a head on their shoulders well enough to use and/or modify it further. Speaking of which, hopefully someone else will find this useful!
 
Gregg Bolinger
Ranch Hand
Posts: 15304
6
Mac OS X IntelliJ IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Charles Rector:
I tossed in some comments here and there where I thought they might do some good. But I figure anybody with a reason to use this class probably already has a head on their shoulders well enough to use and/or modify it further.



You know what happens when you assume don't you? Thanks for posting the code for us.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, thanks for the code! I posted a link to this thread in the bug database, so that others can find it, too...
 
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Charles,

Is there anyway that you can post this code again? I also need to adjust the dirty area of JViewport. I would like to present a translucent area around the border of the JViewport but still have the JViewport implementation use the copyArea for the smaller region that is not affected by the translucent overlay. It sounds like the work that you did on JViewport could be used or modified to fit this scenario.

Thanks!
reply
    Bookmark Topic Watch Topic
  • New Topic