开发者

Issue with JTextPane with background image and clipping rectangle

I have a problem with Swing that I just don't find the reason for. I have a JTextPane that has been extended to show a background image. This can be either a raster image (shown via the Standard Java APIs) or a SVG vector image (shown via SVG Salamander).

Since I want the text pane to have an area at the top used as a margin that won't show any text, I do the following: I override paintComponent(), paint the background image, then call super.paintComponent() so that the text and so on will be shown, and finally I paint a piece of the background image again but with a clipping rectangle to cover only the text that is in the top margin area.

This works perfectly fine except for a little glitch that I've been battling for days: with the raster image, if I select text in the text pane, the text is removed rather than highlighted. That is, when I select text, the background image is shown over the parts that I'm selecting. I don't understand why this could be, since the first call that paints the image is called before super.paintComponent(), the second call has a clip开发者_StackOverflow社区ping rectangle so it only paints over the margin, and everything works fine if I don't make selections. Some extra clues:

  • I do know it's something related to the second call, since if I comment it I don't have this issue (then I don't have the margin though).
  • Curiously it doesn't happen when the background is a vector image, only with a raster image.

Here is the code for my paintComponent() method:

public void paintComponent(Graphics g)
{
    Rectangle rect = null;
    if ( rasterBackgroundImage != null )
    {
        rect = getVisibleRect();
        g.drawImage(rasterBackgroundImage.getImage(),rect.x,rect.y,rect.width,rect.height,this);
    }
    if ( vectorBackgroundImage != null )
    {
        rect = getVisibleRect();
        vectorBackgroundImage.setPreferredSize(new Dimension(rect.width,rect.height));
        vectorBackgroundImage.setScaleToFit(true);
        vectorBackgroundImage.paintIcon(this, g, rect.x, rect.y);
    }

    super.paintComponent(g);

    //if we want a non-scrolling top margin
    if ( rasterBackgroundImage != null )
    {
        g.setClip(rect.x,rect.y,rect.width,getMargin().top);
        g.drawImage(rasterBackgroundImage.getImage(),rect.x,rect.y,rect.width,rect.height,this);
    }
    if ( vectorBackgroundImage != null )
    {
        g.setClip(rect.x,rect.y,rect.width,getMargin().top);
        vectorBackgroundImage.setPreferredSize(new Dimension(rect.width,rect.height));
        vectorBackgroundImage.paintIcon(this, g, rect.x, rect.y);
    }

}

If anyone would like to have a look at the whole class, it is here: http://code.google.com/p/aetheria/source/browse/trunk/age/src/eu/irreality/age/swing/FancyJTextPane.java?r=301

Note that I'm not asking for a fix since it seems that the problem is in interaction with other classes. That's why I didn't provide an SSCCE: I tried to build one, but if I use this class in isolation... it actually WORKS. I haven't been able to reproduce the problem outside the whole system and I have no idea which interaction produces it. But I would be very grateful to anyone providing hints pointing me in the right direction - maybe someone has seen this kind of thing before and could have a clue of what might be the cause...

Update: I have managed to work around the issue, by ceasing to use setClip(). I found this answer recommending not to use setClip() in paintComponent(): java swing clipping problem

Instead of using a clipping rectangle, I now create a subimage containing the top part of the image which I want to draw on the margin, and draw that directly without calling setClip(). It's probably quite inefficient since I'm storing two images in memory when one should be enough, but at least it Works(tm). If anyone is curious about seeing this hack, it's here (the code is a bit dirty at the moment): http://code.google.com/p/aetheria/source/browse/trunk/age/src/eu/irreality/age/swing/FancyJTextPane.java?r=305

Still if anyone is able to figure out the exact cause why using setClip() in this way causes these issues, or knows of an efficient way to solve this, it would be interesting. Thanks for all the answers! :)


why bother with painting Image by using paintComponent(s) if is there exist JLabel and How To Use Icon, other valuable informations are described in Performing Custom Painting and extended in 2D Graphics, tons examples here and 2D-Graphics-GUI


In addition to @mKorbel's helpful links, here are a few ideas:

  • Check the layout of parent containers, noting insets and defaults such as BorderLayout for JFrame and FlowLayout for JPanel. As you've observed, contrasting colors can help.

  • On the parent Window, pack() should be called at least once, as it "causes this Window to be sized to fit the preferred size and layouts of its subcomponents."

  • Critically examine the use of setPreferredSize() in one case and not the other, noting that you may need to revalidate() as well as repaint().

  • Review the examples in How to Use Editor Panes and Text Panes.

  • As an aside, consider whether De Morgan's laws may simplify the predicate in the set*BackgroundImage() methods:

    setOpaque(!(rasterBackgroundImage == null && vectorBackgroundImage == null));
    
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜