2016-01-19 33 views
5

Non ho mai lavorato con Timer s prima quindi il mio problema è probabilmente uno stupido. Il mio programma disegna un cerchio che è rosso e dopo secondi casuali il cerchio dovrebbe cambiare il suo colore in verde. Ho appena fatto uno swing timer come puoi vedere qui sotto nel codice. Ed entra nel metodo actionPerformed() ma non cambia colore. Potresti aiutarmi in qualche modo a risolvere il mio problema con il cambiamento dei colori?La pittura all'interno del timer di pendolamento non funziona

Il mio codice:

package igrica; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.Random; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 


public class ChangingCircle implements ActionListener{ 

JFrame frame; 

Timer timer; 
Random r; 

public static void main(String[] args) { 
    ChangingCircle gui = new ChangingCircle(); 
    gui.go(); 
} 

public void go() { 
    frame = new JFrame(); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    MyPanel panel = new MyPanel(); 

    frame.getContentPane().add(BorderLayout.CENTER, panel); 
    frame.setSize(300, 300); 
    frame.setVisible(true); 
} 

public void actionPerformed(ActionEvent event) { 
    frame.repaint(); 
} 

class MyPanel extends JPanel { 
    public void paintComponent(Graphics g) { 


     g.setColor(Color.red); 
     g.fillOval(100, 100, 100, 100); 

     Random r = new Random(); 

     Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() { 
      public void actionPerformed(ActionEvent ev) { 
       System.out.println("Timer out"); 
       g.setColor(Color.green); 
       g.fillOval(100, 100, 100, 100); 
      } 
     }); 
     timer.start(); 
    } 
} 
} 
+0

Consiglio in italiano: non iniziare ogni frase con "Così", non stai raccontando una storia. – user1803551

+0

So che non dovrei, ma non so con quale parola iniziare una frase. xD –

+0

Basta rimuovere "So" e la frase va bene così com'è. – user1803551

risposta

8

C'è abbastanza casino nel codice. Prova questo:

public class ChangingCircle { 

    Color color = Color.RED; 
    MyPanel panel = new MyPanel(); 

    public static void main(String[] args) { 

     SwingUtilities.invokeLater(() -> { 
      ChangingCircle gui = new ChangingCircle(); 
      gui.go(); 
     }); 
    } 

    public void go() { 

     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     frame.getContentPane().add(panel, BorderLayout.CENTER); 
     frame.pack(); 
     frame.setVisible(true); 

     Random r = new Random(); 
     Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() { 

      public void actionPerformed(ActionEvent ev) { 

       System.out.println("Timer"); 
       color = Color.GREEN; 
       panel.repaint(); 
      } 
     }); 
     timer.setRepeats(false); 
     timer.start(); 
    } 

    class MyPanel extends JPanel { 

     private int size = 100, loc = 100; 

     @Override 
     public void paintComponent(Graphics g) { 

      super.paintComponent(g); 
      g.setColor(color); 
      g.fillOval(loc, loc, size, size); 
     } 

     @Override 
     public Dimension getPreferredSize() { 

      return new Dimension(size + loc, size + loc); 
     } 
    } 
} 

L'idea è che il timer cambia solo la proprietà della forma da trarre e quindi chiama repaint() per riflettere il cambiamento. Il paintComponent viene chiamato ogni volta che è necessario, anche in rapida successione e dovrebbe tornare rapidamente.

Note specifiche:

  • Start Swing from the EDT.
  • Creare e avviare il timer dall'esterno di paintComponent poiché viene chiamato più volte e ciò creerà e avvierà molti timer.
  • Probabilmente si dovrebbe impostare il timer per non ripetere.
  • Chiamare super.paintComponent(g); come prima cosa all'interno di paintComponent.
  • Sembra che tu abbia un ActionListener che non fa nulla.

Consigli generali:

  • utilizzare il @Override annotazioni quando applicabile.
  • Chiama il numero pack() sul telaio invece di impostarne le dimensioni manualmente e il metodo @Override del componente su cui si dipinge il getPreferredSize.Restituisci una dimensione significativa in base a ciò che disegni.
  • Utilizzare add(component, location) e non viceversa (obsoleto).
  • Non utilizzare i campi quando le variabili locali verranno eseguite (ad esempio, Random r).
  • Utilizzare i nomi di costanti maiuscole (Color.RED anziché Color.red).
+0

Grazie, lo hai descritto così dettagliato! –

6

non avviare un timer all'interno di un metodo di paintComponent. Questo metodo dovrebbe essere solo per la pittura e la pittura. Avvia invece il timer nel tuo costruttore e all'interno dell'azione del tuo timerPerferito e chiama repaint(), cambia lo stato di un campo della classe e usa quelle informazioni all'interno di paintComponent che usa quel campo per disegnare qualsiasi nuova informazione.

ad es.

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.Random; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

public class ChangingCircle { 
    JFrame frame; 

    public static void main(String[] args) { 
     ChangingCircle gui = new ChangingCircle(); 
     gui.go(); 
    } 

    public void go() { 
     frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     MyPanel panel = new MyPanel(); 

     frame.getContentPane().add(BorderLayout.CENTER, panel); 
     frame.setSize(300, 300); 
     frame.setVisible(true); 
    } 

    public void actionPerformed(ActionEvent event) { 
     frame.repaint(); 
    } 

    class MyPanel extends JPanel { 
     private Random r = new Random(); 
     private boolean draw = false; 

     public MyPanel() { 
      Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() { 
       public void actionPerformed(ActionEvent ev) { 
        draw = true; 
        repaint(); 
       } 
      }); 
      timer.setRepeats(false); 
      timer.start(); 
     } 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (draw) { 
       g.setColor(Color.red); 
       g.fillOval(100, 100, 100, 100); 
      } 
     } 
    } 
} 

Inoltre, non dimenticare di chiamare il metodo paintComponent del super dall'override.

Se è necessario cambiare i colori, assegnare a JPanel un campo Colore, ad esempio chiamato color e modificarne il valore dall'interno del timer, quindi chiamare repaint(). Sempre all'interno di paintComponent, usa il valore di quel campo per disegnare l'ovale con. Anche in questa situazione, il Timer dovrebbe ripetere, quindi eliminare timer.setRepeats(false) in quella situazione.

+0

ma cosa fare se sarà necessario cambiare continuamente colore da ex. dal rosso al verde e poi dal verde al rosso, funzionerà anche questo? –

+0

@DomagojSabolic: quindi nel Timer cambia lo stato di un campo Colore e lo usa nel metodo paintComponent. –

+0

@DomagojSabolic: vedere le modifiche per rispondere. –

0

Il timer funziona in modo asincrono e paintComponent termina prima di terminare il lavoro del timer.

+0

Ma il mio System.out.println funziona e stampa ogni volta che il timer termina –

+0

in questo esempio si ha un JFrame e un Jpanel, se si aggiungono molti componenti questa implementazione genererà eccezioni perché quando il timer tenta di apportare modifiche a g , nello stesso tempo un altro componente utilizzerà la stessa istanza di g per ridipingere –

+0

Non vedo come questo risponda alla domanda. 'paintComponent' * dovrebbe/can * terminare prima dell'avvio del timer o eseguire la sua azione. La questione dell'asincronismo è irrilevante. – user1803551