2009-04-11 14 views
1

Artikel ist eine einfache Modellklasse.Swing: Warum wird meine benutzerdefinierte Komponente nicht neu streichen?

ItemComponent ist eine Ansicht für ein Objekt, das nur einfache Rechtecke an einer bestimmten Stelle zeichnet. Eine Reihe von ItemComponent-Instanzen wird in eine übergeordnete Komponente eingefügt, die dem JFrame der Anwendung hinzugefügt wird (momentan nur eine einfache Shell).

Die Ansicht hat zwei verschiedene Anzeigestile. Ich möchte einige Eigenschaften des Modells anpassen und möglicherweise den Status ändern (der den Stil steuert) und dann update() aufrufen, um neu zu zeichnen.

Das Problem ist, soweit ich das beurteilen kann ... paint() wird nur einmal aufgerufen. repaint() scheint keine Wirkung zu haben.

Was ist los?

Ich bin kein Swing-Programmierer und habe das aus Beispielen zusammengestöpselt, also erwarte ich, dass es hier etwas Triviales sein kann, das ich nicht verstehe.

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); 
     } 
    } 
} 

Hinweis: ich in repaint verfolgt() und einen Punkt gefunden, wo isDisplayable() überprüft wurde, und es ist falsch zurück. Es stellt sicher, dass getPeer()! = Null ist.

Also hat meine Komponente keinen Partner? Was ist damit? Es wurde einem Container hinzugefügt, der selbst zum Rest der App hinzugefügt wird. Und es wird einmal gemalt, also weiß ich, dass es sichtbar ist.

+0

Ein Peer ist nur für AWT-Komponenten verfügbar (der Peer ist die reale Komponente des nativen Fenstersystems, die zur Komponente gehört), die meisten Swing-Komponenten haben keinen Peer. Warum arbeitest du sowieso an addNotify? –

Antwort

2

Ich entschuldige mich bei den Leuten, die das schon angeschaut haben. Ich getrimmt den Code ein wenig nach unten für die Buchung und versehentlich eine Schlüsselrolle ausgelassen:

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

ich dies mit einigen Setup zu tun, sobald es hinzugefügt wurde. Stellt sich heraus, es ist ziemlich wichtig, dass Sie dies nicht überschreiben, oder zumindest müssen Sie super.addNotify() aufrufen, oder eine ganze Reihe wichtiger Initialisierung passiert nicht.

es diese Änderung das Problem behoben:

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

Froh, dass Sie es herausgefunden haben. Danke fürs Nachfassen. Ich lerne immer noch Java selbst. Ich werde diese Information zu meinem "for-future-reference" Teil meines Gehirns hinzufügen. –

1

Die Antwort ist irgendwo here. Besonders der Abschnitt über Painting in Swing. Ich bin verwirrt, dass das Verschieben des Rendering-Codes in paintComponent() nicht so funktioniert, wie es von Johannes Rössel vorgeschlagen wurde. Da die Dokumentation sagt, es ..

Die Farbe Methoden

Die Regeln, die gelten für zu AWTs Leichtbaukomponenten gelten auch Swing-Komponenten - zum Beispiel, paint() aufgerufen wird, wenn es Zeit ist, zu machen - außer dass Schwingen weiter die Farbe Faktoren() aufrufen, in drei getrennte Verfahren, die in der folgenden Reihenfolge aufgerufen werden:

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

Swing-Programme sollten paintComponent() überschreiben paint() überschreiben.

0

Sie würden wollen repaint() anrufen führen, dass Ihr JComponent sich Update statt neu streichen.

Anstatt paint(Graphics g) außer Kraft zu setzen, überschreiben Sie stattdessen paintComponent(Graphics g) und platzieren Sie Ihren benutzerdefinierten Rendering-Code.

Stellen Sie sicher, dass Sie die erste Zeile der überschriebenen Methode super.paintComponent(g) aufrufen, da eine Schlüsselinitialisierung stattfindet.

Wichtig ist auch, dass abhängig vom LayoutManager des Containers, zu dem Ihre ItemComponent hinzugefügt wird, die Größe möglicherweise explizit festgelegt werden muss. Ich sehe, Sie versuchen, dies in der update() -Methode zu tun. Sie sollten die Größe nur einmal festlegen, möglicherweise am besten im Code, der Ihre Komponente erstellt, und sie einem Container hinzufügen.

Für das, was Sie versuchen, sollte es nur notwendig sein, paintComponent() zu überschreiben. Sie sollten alle anderen überschriebenen Methoden entfernen.

Rufen Sie repaint() von setState(). Wenn die Größe der Komponente von dem übergebenen Status abhängt, möchten Sie möglicherweise setSize() kurz vor repaint() aufrufen.

Hoffnung, das hilft.

Verwandte Themen