具有背景图像和剪切矩形的 JTextPane 问题

发布于 2024-11-15 23:03:17 字数 2905 浏览 2 评论 0原文

我在使用 Swing 时遇到问题,但找不到原因。我有一个 JTextPane 已扩展为显示背景图像。这可以是光栅图像(通过标准 Java API 显示)或 SVG 矢量图像(通过 SVG Salamander 显示)。

由于我希望文本窗格的顶部有一个区域用作边距,不会显示任何文本,因此我执行以下操作:我重写 PaintComponent(),绘制背景图像,然后调用 super.paintComponent() 以便将显示文本等,最后我再次绘制一块背景图像,但使用剪切矩形仅覆盖顶部边距区域中的文本。

除了我几天来一直在努力解决的一个小问题之外,这工作得很好:对于光栅图像,如果我在文本窗格中选择文本,文本将被删除而不是突出显示。也就是说,当我选择文本时,背景图像会显示在我选择的部分上。我不明白为什么会这样,因为绘制图像的第一个调用是在 super.paintComponent() 之前调用的,第二个调用有一个剪切矩形,因此它只在边缘上绘制,如果我不这样做,一切都会正常工作不要做出选择。一些额外的线索:

  • 我确实知道这与第二次通话有关,因为如果我评论它,我就没有这个问题(但我没有余量)。
  • 奇怪的是,当背景是矢量图像而只有光栅图像时,这种情况不会发生。

这是我的paintComponent()方法的代码:

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);
    }

}

如果有人想查看整个类,就在这里:http://code.google.com/p/aetheria/source/browse/trunk/age/src/eu/irreality/age/swing/FancyJTextPane.java?r=301

请注意,我'我不要求修复,因为问题似乎出在与其他类的交互中。这就是为什么我没有提供 SSCCE:我尝试构建一个,但如果我单独使用这个类......它实际上是有效的。我无法在整个系统之外重现该问题,并且我不知道是哪种交互产生的。但我将非常感谢任何人提供提示,为我指明正确的方向 - 也许有人以前见过这种事情,并且可以知道可能的原因......

更新:我已经通过停止使用 setClip() 设法解决了这个问题。我发现这个答案建议不要在paintComponent()中使用setClip():java swing裁剪问题

我现在不使用剪切矩形,而是创建一个子图像,其中包含要在边缘绘制的图像的顶部部分,并直接绘制它而不调用 setClip()。这可能效率很低,因为我在内存中存储了两张图像,而一张图像就足够了,但至少它可以工作(tm)。如果有人对这个黑客感到好奇,就在这里(目前代码有点脏):http://code.google.com/p/aetheria/source/browse/trunk/age/src/eu/irreality/age/swing/FancyJTextPane.java?r=305

仍然,如果有人能够找出以这种方式使用 setClip() 导致这些问题的确切原因,或者知道解决这个问题的有效方法,这会很有趣。感谢所有的答案! :)

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 clipping 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! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鹿港小镇 2024-11-22 23:03:17

如果存在JLabel<,为什么要费心使用paintComponent(s)来绘制图像/a> 和如何使用图标,其他有价值的信息是描述于执行自定义绘画并在 2D 图形,大量示例 此处此处 java2s.com/Code/Java/2D-Graphics-GUI/Catalog2D-Graphics-GUI.htm" rel="nofollow">2D-Graphics-GUI

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

找个人就嫁了吧 2024-11-22 23:03:17

除了 @mKorbel 的有用链接之外,这里还有一些想法:

  • 检查父容器的布局,注意插入和默认值,例如 JFrameBorderLayout JPanel 的 >FlowLayout。正如您所观察到的,对比色会有所帮助。

  • 在父窗口上,pack() 应至少调用一次,因为它“导致此 Window 的大小适合首选大小及其子组件的布局。”

  • 严格检查在一种情况下使用 setPreferredSize() 的情况,而不是在另一种情况下,注意您可能需要 revalidate() 以及 repaint( )

  • 查看如何使用编辑器窗格和文本中的示例窗格

  • 顺便说一句,考虑德摩根定律是否可以简化<代码>set*BackgroundImage()方法:

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

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));
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文