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;
}
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:
No, you have one view updating another; you need two views responding to one model. This related example may offer some insight.
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.
Yes,
repaint()
, but it should be done in theButtonHandler
forView
: