为什么 repaint() 从未调用 PaintComponent() ?
我一直在开发一个将自定义 JComponent 绘制到 JLayeredPane 上的程序,但是对组件上的所有 repaint() 调用似乎都没有执行任何操作,但在重新调整窗口大小时会自动调用 PaintComponent 方法。
我一直在遵循这里给出的一些建议: 调用过paint()/paintComponent()?
有什么想法可以阻止通话吗?预先感谢:)
这是 View 和 SVGElementContainer 的代码,view.setFile() 是入口点,因为它在需要显示新文档时被调用。
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()));
}
}
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()));
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我看到您正在调用 setOpaque(false)。从 setOpaque javadoc 中,强调我的:
如果为 true,则组件将绘制其边界内的每个像素。否则,组件可能无法绘制其部分或全部像素,从而允许底层像素显示出来。
这个“可能”是在 repaint() 调用期间第一次调用后 PaintComponent() 没有被调用的原因。 Swing 可以判定组件没有“改变”,因此不需要重新绘制。
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.
您的代码在这些概念上是错误的。
a) 切勿调用 setSize() 方法。这是布局管理器的工作。您应该通过重写 getPreferredSize() 等方法来向布局管理器提供提示,以返回组件的首选大小
b) 不要重写 revalidate() 方法。该技巧的要点是使用如下代码:
但我真的不知道你的所有代码应该做什么,所以我无法确定你的代码是否有意义。我还发现你扩展 JLayeredPane 很奇怪。
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:
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.
我可以看到扩展
JPanel
来获取缓冲和 UI 委托,但不透明度取决于 L&F 。相反,您可能应该从JComponent
开始并实现EventListenerList
为您的(假设的)SVGEvent
提供管道。I can see extending
JPanel
to get the buffering and UI delegate, but the opacity is L&F dependent. Instead, you should probably start withJComponent
and implement theEventListenerList
plumbing for your (hypothetical)SVGEvent
.