metodo repaint Java non funziona quando viene chiamato da un'altra classe
Domanda
Sono stato codificare fino Java con Netbeans per circa un anno, e ho scritto un sacco di codice manipolazione dei dati che riporta i grafici sullo schermo. Io in genere pianta un oggetto JPanel nella mia finestra principale, personalizzati in scrittura pittura di codice, e chiamare il metodo repaint (), se necessario.
Ma oggi, per la prima volta, ho provato a richiamare un ridisegno su un pannello da una classe (oggetto) diverso da quello che conteneva il pannello. Anche se il compilatore ha trovato sbagliato nulla con questo, e in modalità debug, single-passo correttamente alla chiamata esterna al ridisegno, non riverniciare è effettivamente verificata, e il codice non ha in realtà passo nel metodo repaint.
Ho scritto un programma minimale per dimostrare il problema, come illustrato di seguito (viene omesso principale, dal momento che contiene soltanto il codice per impostare i due pannelli sullo schermo.)
--- Descrizione delle classi, prima contiene la superficie di disegno, altri la chiamata ridisegno ---
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Panel1 extends JComponent
{
GraphPnl graphPnl;
boolean colorFlag;
public Panel1()
{
setLayout(null);
colorFlag = true;
graphPnl = new GraphPnl();
graphPnl.setBounds(10, 10, 110, 110);
graphPnl.setBackground(Color.black);
add(graphPnl);
}//Panel1()
public class GraphPnl extends JPanel
{
//just draws a line segment, toggling color
@Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (colorFlag) {g2.setColor(Color.red);} else {g2.setColor(Color.green);}
g2.drawLine(10, 10, 50, 50);
}//paint
}//GraphPnl
}//Panel1
import javax.swing.*;
import java.awt.event.*;
public class Panel2 extends JComponent
{
JButton testBtn;
TestAction testAction;
Panel1 p1;
public Panel2()
{
p1 = new Panel1();
testBtn = new JButton("Click");
testBtn.setBounds(10, 10, 80, 30);
add(testBtn);
testAction = new TestAction();
testBtn.addActionListener(testAction);
}//Panel2()
public class TestAction implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
p1.colorFlag = ! p1.colorFlag;
p1.graphPnl.repaint();
}
}//TestAction
}//Panel2
Se qualcuno ha qualche intuizioni in questo, o sa di una soluzione, sarei molto felice di sentire da voi.
Grazie in anticipo per eventuali approfondimenti.
John Doner
Soluzione
Credo che quando si sta disegnando un JComponent, l'area di visualizzazione è impostata su quella JComponent. Quindi, se gli altri componenti cercano di dipingere (o se si chiama il loro ridisegno), non lo faranno, a causa della saturazione.
Altri suggerimenti
principale è omesso, in quanto contiene soltanto il codice per impostare i due pannelli sullo schermo.)
Bene, per definizione, quando si ha un problema che non si sa quale codice è o non è relativo fino a quando il problema è risolto. Quindi un completo SSCCE dovrebbe essere pubblicato.
Come un ipotesi direi il componente ha una dimensione di 0 quindi non c'è nulla di dipingere.
Io in genere pianta un oggetto JPanel nella mia finestra principale, personalizzati in scrittura pittura di codice, e chiamare il repaint () Metodo secondo necessità
Probabilmente è stato fortunato perché si è aggiunto il pannello al centro di una BorderLayout che dà automaticamente il pannello di tutto lo spazio a disposizione del telaio.
di trashgod esempio mostra un modo per impostare la dimensione preferita di un componente personalizzato. Un altro modo è quello di sovrascrivere il metodo getPreferredSize () per restituire il valore corretto.
Si dovrebbe davvero imparare ad usare gestore di layout piuttosto che utilizzare i layout nulli ed eviterete problemi come questo in futuro. Non v'è alcuna necessità di utilizzare un layout nulla a meno che non si dispone di un tipo drag / drop di applicazione.
"programmi dell'oscillazione dovrebbe ignorare paintComponent()
invece di override paint()
." - Pittura in AWT e swing:. I metodi di vernice
main
viene omesso, in quanto contiene soltanto il codice per impostare i due pannelli sullo schermo.
Verificare che si costruisce la vostra interfaccia grafica sul EDT, come mostrato in questo articolo Le discussioni iniziali .
Addendum: Ecco un esempio che mostra entrambi i principi:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** @see http://stackoverflow.com/questions/4282159 */
public class GraphPanel extends JPanel {
private boolean colorFlag;
public GraphPanel() {
this.setPreferredSize(new Dimension(640, 480));
}
public void toggle() {
colorFlag = !colorFlag;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (colorFlag) {
g2.setColor(Color.red);
} else {
g2.setColor(Color.blue);
}
g2.drawLine(0, 0, getWidth(), getHeight());
}
private void display() {
JFrame f = new JFrame("GraphPanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this, BorderLayout.CENTER);
f.add(new ControlPanel(this), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new GraphPanel().display();
}
});
}
}
class ControlPanel extends JPanel {
public ControlPanel(final GraphPanel gp) {
this.add(new JButton(new AbstractAction("Click") {
@Override
public void actionPerformed(ActionEvent e) {
gp.toggle();
gp.repaint();
}
}));
}
}
Addendum: Come notato nel commento di @ camickr, A visiva Guida ai gestori di layout può aiutare a guidare la selezione di layout.