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。
所以我的组件没有同行?那是怎么回事?它被添加到一个容器中,该容器本身被添加到应用程序的其余部分。它被画了一次,所以我知道它是可见的。
答案 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()
。
希望有所帮助。