在另一个组件中绘制外部组件(即属于不同框架的内容窗格)

发布于 2024-10-21 14:52:24 字数 3532 浏览 5 评论 0原文

大家好。 我想绘制一个外部组件(即属于不同框架的内容窗格),我们将其称为框架 B,位于框架 A 中的组件内。

问题是,当我绘制该组件时,它会被绘制同样在框架 A 的内容窗格中,当调整框架大小时,它也会闪烁或变得丑陋(即在组件内绘制几次,出现一些蓝色方块等)。例如,如果我尝试在绘制之前缩放或平移外部组件,则问题会变得更加明显。

过了一会儿,我想,我整理了一下。但我对这个解决方案感觉不太好,出于某种原因,我相信可能有更好、更合适的解决方案。这里我需要你。 :)

这个问题更多的是要求解释为什么外部组件被错误地绘制而不在组件内部绘制之前和之后操纵它的双缓冲功能。例如,使用任意一对 setDoubleBuffered(false) 和 setDoubleBuffered(true) 或者 disableDoubleBuffering(jP)和enableDoubleBuffering(jP)

分别在调用外部组件的paint方法之前和之后

。先感谢您。显示问题的 SSCCE 如下所示。


import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;

public class PaintForeignComponentSSCCE extends JFrame
{
    public static void main(String[] args) throws IOException
    {
        //foreign panel
        JPanel fp = new JPanel();
        fp.setBackground(Color.PINK);
        fp.setPreferredSize(new Dimension(200, 300));
        //component in which the foreign panel is painted
        ForeignComponentPainter fcp = new ForeignComponentPainter(fp);
        fcp.setPreferredSize(new Dimension(600, 600));
        //main frame's content
        JPanel contentPane = new JPanel();
        contentPane.setBackground(Color.BLUE);
        contentPane.add(fcp);
        //main frame
        JFrame f = new PaintForeignComponentSSCCE();
        f.setContentPane(contentPane);
        f.setSize(700, 500);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);             
        //foreign panel frame
        JFrame fpf = new JFrame();
        JPanel panelFrameContent = new JPanel();
        panelFrameContent.add(fp);
        fpf.setContentPane(panelFrameContent);
        fpf.setSize(400, 400);
        fpf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        fpf.setVisible(true);
    }
}

class ForeignComponentPainter extends JButton
{
    private static final long serialVersionUID = 1L;
    private JPanel jP;

    public ForeignComponentPainter(JPanel jP)
    {
        super();
        this.jP = jP;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawString("OIOI", 50, 50);
        //g2.translate(100, 50);
        //g2.scale(.5, .5);
//      jP.setDoubleBuffered(false);
//      disableDoubleBuffering(jP);
        jP.paint(g2);
//      jP.setDoubleBuffered(true);
//      enableDoubleBuffering(jP);
        //g2.scale(1/.5, 1/.5);
    }   
    public static void disableDoubleBuffering(Component c)
    {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(false);
    }
    public static void enableDoubleBuffering(Component c)
    {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(true);
    }
}

与 SSCCE 示例无关。 以下内容与问题本身无关。 这段代码的目的是展示我如何在组件中实现 Printable,我也想以打印预览方式呈现该组件。 print调用组件的paint(如下所示)。


public int print(Graphics g, PageFormat pageFormat, int pageIndex)
{ 
   if(pageIndex >= pageHeights.size()) 
      return NO_SUCH_PAGE; 
   int savedPage = currentPageIndex; 
   currentPageIndex = pageIndex; 
   Graphics2D g2 = (Graphics2D) g; 
   paint(g2); 
   currentPageIndex = savedPage; 
   return PAGE_EXISTS; 
} 

Hallo all.
I want to paint a foreign component (i.e. belonging to a different frame's content pane), lets call it frame B, inside a component in frame A.

The problem is that when I paint the component it is painted also in the content pane of the frame A, also it flickers or all gets ugly when the frame is re-sized (i.e. painted few times inside the component, some blue squares are appearing, etc.). The issue becomes more visible if I try to, for example, scale or translate the foreign component before painting.

After a while I sorted it, I think. But I do not feel good with this solution, for some reason I believe there might be a better one, a more appropriate one. Here I need you. :)

This question is more a call for an explanation why the foreign component is painted incorrectly without manipulating it's double buffering feature before and after the paint inside the component. For example with use of either pair of
setDoubleBuffered(false) and setDoubleBuffered(true)
or
disableDoubleBuffering(jP) and enableDoubleBuffering(jP)

respectively before and after the call to the foreign component's paint method.

Thank You in advance. The SSCCE showing the problem is presented below.


import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;

public class PaintForeignComponentSSCCE extends JFrame
{
    public static void main(String[] args) throws IOException
    {
        //foreign panel
        JPanel fp = new JPanel();
        fp.setBackground(Color.PINK);
        fp.setPreferredSize(new Dimension(200, 300));
        //component in which the foreign panel is painted
        ForeignComponentPainter fcp = new ForeignComponentPainter(fp);
        fcp.setPreferredSize(new Dimension(600, 600));
        //main frame's content
        JPanel contentPane = new JPanel();
        contentPane.setBackground(Color.BLUE);
        contentPane.add(fcp);
        //main frame
        JFrame f = new PaintForeignComponentSSCCE();
        f.setContentPane(contentPane);
        f.setSize(700, 500);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);             
        //foreign panel frame
        JFrame fpf = new JFrame();
        JPanel panelFrameContent = new JPanel();
        panelFrameContent.add(fp);
        fpf.setContentPane(panelFrameContent);
        fpf.setSize(400, 400);
        fpf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        fpf.setVisible(true);
    }
}

class ForeignComponentPainter extends JButton
{
    private static final long serialVersionUID = 1L;
    private JPanel jP;

    public ForeignComponentPainter(JPanel jP)
    {
        super();
        this.jP = jP;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawString("OIOI", 50, 50);
        //g2.translate(100, 50);
        //g2.scale(.5, .5);
//      jP.setDoubleBuffered(false);
//      disableDoubleBuffering(jP);
        jP.paint(g2);
//      jP.setDoubleBuffered(true);
//      enableDoubleBuffering(jP);
        //g2.scale(1/.5, 1/.5);
    }   
    public static void disableDoubleBuffering(Component c)
    {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(false);
    }
    public static void enableDoubleBuffering(Component c)
    {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(true);
    }
}

Not related to the SSCCE example. The below is unrelated to the problem itself.
This piece of code serves the purpose of presentation of how I am implementing Printable in the component which I also want to render in a print preview fashion. The print calls paint of the component (as shown below).


public int print(Graphics g, PageFormat pageFormat, int pageIndex)
{ 
   if(pageIndex >= pageHeights.size()) 
      return NO_SUCH_PAGE; 
   int savedPage = currentPageIndex; 
   currentPageIndex = pageIndex; 
   Graphics2D g2 = (Graphics2D) g; 
   paint(g2); 
   currentPageIndex = savedPage; 
   return PAGE_EXISTS; 
} 

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

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

发布评论

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

评论(1

原谅我要高飞 2024-10-28 14:52:24

抱歉,我无法直接解决您的问题,但可以通过对通用模型有两种不同的视图来避免它。如如何编写文档监听器所示,可以更新多个视图文档的a>。您的模型和视图可能不同,但该概念仍然适用。

附录:

我想这就是我现在正在做的事情,不是吗?我有一个模型,即“外部”组件,以及两个视图,一个执行默认绘制,第二个执行自定义绘制。

不,您有一个视图更新另一个视图;您需要两个视图来响应一个模型。这个相关的示例可能会提供一些见解。

我仍然对有关这幅错误绘画的原因的建议感兴趣。

在我看来,将两个组件的更新交错的尝试从根本上来说是有缺陷的;它颠覆了 Swing 中绘画的正常流程。在我的平台上,我只看到非常短暂的闪烁,看不到任何偶然的绘画。尽管有可能在一个系统上获得令人满意的结果,但这种安排在不同的实现中将是不可靠的。

简单调用标签重绘并将其放置在 ModelObserverupdate() 方法中是合适的解决方案吗?

是的,repaint(),但应该在 ButtonHandler 中完成对于查看

private class ButtonHandler implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        PieceButton pb = (PieceButton) e.getSource();
        icon.color = pb.piece.color;
        label.repaint();
        model.check(pb.piece);
    }
}

Sorry, I can't address your question directly, but it may be possible to avoid it by having two different views of a common model. As shown in How to Write a Document Listener, it is possible to update more than one view of a Document. Your model and view(s) might be different, but the concept would still apply.

Addendum:

I think that is what I am doing at the moment, isn't it? I have one model i.e. the 'foreign' component, and two views one doing default paint and second custom paint.

No, you have one view updating another; you need two views responding to one model. This related example may offer some insight.

I am still interested in suggestions as to the reasons of this erroneous painting.

The attempt to interleave the updates of two components is, IMO, fundamentally flawed; it subverts the normal process of Painting in Swing. On my platform, I see only a very brief flicker and no adventitious painting. Although it may be possible to obtain satisfactory results on one system, the arrangement would be unreliable across implementations.

Is a simple call to repaint of the label, placed in the ModelObserver's update() method the appropriate solution?

Yes, repaint(), but it should be done in the ButtonHandler for View:

private class ButtonHandler implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        PieceButton pb = (PieceButton) e.getSource();
        icon.color = pb.piece.color;
        label.repaint();
        model.check(pb.piece);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文