Swing:为什么我的自定义组件不会重新绘制?

时间:2009-04-11 23:07:47

标签: java user-interface swing

Item是一个简单的模型类。

ItemComponent是一个Item的视图,它只是在给定的点中绘制简单的矩形。一堆ItemComponent实例被放入一个父组件中,该组件被添加到应用程序的JFrame中(现在只是一个简单的shell)。

视图有两种不同的显示样式。我想调整模型的一些属性,并可能更改状态(控制样式),然后调用update()来重绘。

问题是,据我所知... paint()只调用一次。 repaint()似乎没有任何效果。

怎么了?

我不是Swing程序员,并且通过示例将它拼凑在一起,所以我希望它可能是一些微不足道的东西,我不明白。

public class ItemComponent extends JComponent implements ItemView {

    private static final Color COLOR_FILL_NORMAL = new Color(0x008080ff);
    private static final Color COLOR_FILL_TARGET = Color.LIGHT_GRAY;
    private static final Color COLOR_OUTLINE = new Color(0x00333333);

    Item item;
    RoundRectangle2D rect;
    State state = State.NORMAL;
    float alpha = 1.0f;

    public ItemComponent(Item item) {
        this.item = item;
        this.rect = new RoundRectangle2D.Double(0, 0, 0, 0, 5, 5);
        item.setView(this);
    }

    public void setState(State state) {
        this.state = state;
    }

    public void update() {
        System.out.println("ItemComponent.update");
        setLocation(item.getLeft(), 1);
        setSize(item.getWidth(), getParent().getHeight()-1);
        rect.setRoundRect(0, 0, getWidth()-1, getHeight()-1, 5, 5);

        repaint();
        //paintImmediately(getBounds());
    }

    @Override
    public void addNotify() {
        update();
    }

    @Override
    public void paint(Graphics g) {
        System.out.println("paint");

        Graphics2D g2 = (Graphics2D)g;

        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));

        if (state == State.NORMAL) {
            System.out.println("draw normal");
            g2.setPaint(COLOR_FILL_NORMAL); // light blue
            g2.fill(rect);

            g2.setPaint(COLOR_OUTLINE);
            g2.draw(rect);
        }
        else if (state == State.TARGET) {
            System.out.println("draw target");
            g2.setPaint(COLOR_FILL_TARGET);
            g2.fill(rect);

            float[] dashPattern = { 8, 5 };
            g2.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, dashPattern, 0));
            g.setColor(COLOR_OUTLINE);
            g2.draw(rect);
        }
    }
}

提示: 我追溯到repaint()并找到了一个点,其中isDisplayable()被检查,并且它返回false。它确保getPeer()!= null。

所以我的组件没有同行?那是怎么回事?它被添加到一个容器中,该容器本身被添加到应用程序的其余部分。它被画了一次,所以我知道它是可见的。

3 个答案:

答案 0 :(得分:2)

我向已经看过这个的人道歉。我将代码缩减了一段时间,因为发布并无意中遗漏了一个关键部分:

@Override
public void addNotify() {
    update();
}

我在使用它时会在添加后立即进行设置。事实证明,重要的是你不要覆盖它,或者至少你需要调用super.addNotify(),否则就不会发生一大堆重要的初始化。

将其更改为此问题解决了问题:

@Override
public void addNotify() {
    super.addNotify();
    update();
}

答案 1 :(得分:1)

答案是某处here。特别是关于Painting in Swing的部分。令我感到困惑的是,将渲染代码移动到paintComponent()中并不像JohannesRössel所建议的那样有效。正如那里的文件所说..

  

油漆方法

     

适用于AWT的规则   轻量级组件也适用于   Swing组件 - 例如,   paint()在到达时被调用   渲染 - 除了Swing进一步   因素paint()调用三个   单独的方法,在中调用   以下顺序:

protected void paintComponent(Graphics g)
protected void paintBorder(Graphics g)
protected void paintChildren(Graphics g)
     

Swing程序应该覆盖   paintComponent()而不是重写   漆()。

答案 2 :(得分:0)

您需要致电repaint()以使JComponent重绘自己而不是更新。

而不是覆盖paint( Graphics g ),而是覆盖paintComponent( Graphics g )并将自定义呈现代码放在其中。

确保将super.paintComponent( g )作为重写方法的第一行,因为会发生一些键初始化。

另外需要注意的是,根据要添加ItemComponent的容器的LayoutManager,可能需要显式设置大小。我看到你试图在update()方法中这样做。您只需要设置一次大小,也许最好放在构造组件的代码中并将其添加到容器中。

对于您要做的事情,只需要覆盖paintComponent()。您应该删除所有其他被覆盖的方法。

repaint()致电setState()。如果组件的大小取决于传入的状态,您可能希望在setSize()之前调用repaint()

希望有所帮助。