问题
I've been working on an program that draws custom JComponents onto a JLayeredPane however all calls to repaint() on the components seem to do nothing yet the paintComponent method is invoked automatically when the window is re-sized.
I have been following some of the advice given here: Why is paint()/paintComponent() never called?
But none of the solutions seem to fix my problem, update swing components on the EDT, setting component size manually before calling repaint(), calling super.paintComponent(g) in the overridden paintComponent() and calling revalidate() on the frame after adding new components (although this is clearly no the issue in this case)
Any ideas what could be stopping the call? Thanks in advance :)
Here is the code for the View and the SVGElementContainer, view.setFile() is the entry-point as it is invoked when a new document needs to be displayed.
public class View extends JLayeredPane implements SVGViewport {
private SVGDocument document;
//Array list of the SVGElementContainer components
private ArrayList<SVGElementContainer> elemContainers;
private SVGFrame frame;
private int elemCount;
private Border viewBorder;
private int borderWidth = 1;
//panels displayed on the JLayeredPane
private JPanel backgroundPanel;
/** Creates a new view */
public View(SVGFrame frame) {
super();
this.frame = frame;
elemCount = 0;
elemContainers = new ArrayList<SVGElementContainer>();
viewBorder = BorderFactory.createLineBorder(Color.BLACK, borderWidth);
}
public float getViewportWidth() {
return getWidth();
}
public float getViewportHeight() {
return getHeight();
}
// paints all elements and adds them to the JLayeredPane
public void paintAllElements(){
System.out.println("Painting all elements");
// Paint document
for (SVGElement elem : document) {
//only paint stylable (rect, line, circle) elements
if (elem instanceof SVGStylable){
//create a new SVGElementContainer
SVGElementContainer newElemCont = new SVGElementContainer();
//add component to JLayeredPane
elemCount++;
this.add(newElemCont, new Integer(elemCount + 1));
//set the current element within its container and calls repaint() on the component
System.out.println("Painting element #" + elemCount);
newElemCont.setElement(elem);
newElemCont.repaint();
}
else {
System.out.println("Skip painting group element!");
}
}
}
/** Gets the document currently being displayed by the view. */
public SVGDocument getDocument() {
return document;
}
/** Sets the document that the view should display.
*
* @param document the document to set
*/
public void setDocument(SVGDocument document) {
this.document = document;
//paintBackground();
paintAllElements();
revalidate();
}
public void revalidate(){
//calls validate() on the frame in order to display newly added components
frame.getContentPane().validate();
}
}
public class SVGElementContainer extends JPanel{
private SVGElement elem;
public SVGElementContainer(){
super();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("PAINT METHOD CALLED!");
paint2D((Graphics2D) g);
}
//paint the element onto this JComponent
public void paint2D(Graphics2D g){
if (!(elem instanceof SVGStylable)){
System.out.println("Skipping non-stylable element!");
return;
}
setOpaque(false);
Shape shape = elem.createShape();
// get fill stroke and width properties
SVGStylable style = (SVGStylable) elem;
SVGPaint fillPaint = style.getFill();
SVGPaint strokePaint = style.getStroke();
SVGLength strokeWidth = style.getStrokeWidth();
// Fill the interior of the shape
if (fillPaint.getPaintType() == SVGPaint.SVG_PAINTTYPE_RGBCOLOR) {
g.setPaint(fillPaint.getRGBColor());
g.fill(shape);
}
// Stroke the outline of the shape
if (strokePaint.getPaintType() == SVGPaint.SVG_PAINTTYPE_RGBCOLOR) {
Stroke stroke = new BasicStroke(strokeWidth.getValue());
g.setStroke(stroke);
g.setColor(strokePaint.getRGBColor());
g.draw(shape);
}
}
public void setElement(SVGElement elem){
this.elem = elem;
setComponentSize();
}
private void setComponentSize(){
//this.setPreferredSize(new Dimension(
// (int)elem.getDocument().getWidth().getValue(),
// (int)elem.getDocument().getHeight().getValue()));
this.setSize(new Dimension(
(int)elem.getDocument().getWidth().getValue(),
(int)elem.getDocument().getHeight().getValue()));
}
}
回答1:
I see that you're calling setOpaque(false). From the setOpaque javadoc, emphasis mine:
If true the component paints every pixel within its bounds. Otherwise, the component may not paint some or all of its pixels, allowing the underlying pixels to show through.
That "may" be the cause of paintComponent() not being called after the first time during a repaint() call. Swing can decide that the component has not "changed", and thus does not need repainting.
回答2:
setting component size manually before calling repaint(), calling super.paintComponent(g) in the overridden paintComponent() and calling revalidate() on the frame after adding new components
Your code is wrong on these concepts.
a) never invoke the setSize() method. That is the job of the layout manager. You should be providing hints to the layout manager by overriding methods like getPreferredSize() to return the preferred size of your component
b) don't override the revalidate() method. The point of that tip is to use code like:
panel.add( .... );
panel.revalidate();
panel.repaint();
But I don't really know what all your code is supposed to do so I can't tell for sure if your code makes sense. I also find it strange that you are extending a JLayeredPane.
回答3:
I can see extending JPanel
to get the buffering and UI delegate, but the opacity is L&F dependent. Instead, you should probably start with JComponent
and implement the EventListenerList plumbing for your (hypothetical) SVGEvent
.
来源:https://stackoverflow.com/questions/5902974/why-is-paintcomponent-never-called-by-repaint