私の理解: JComponent.repaint()へのSwing呼び出しのコンポーネント/操作のほとんどはスレッドセーフです。つまり、別のスレッド(つまりEDTではなく)から再描画要求が行われても、実際のペイントはEDTのみ。下記のコードスニペットはこれを示しています。これは問題 - 再描画が()にかかわらずそのスレッドから、それが呼び出されていないのが呼び出されたとき、絵がEDTで行われることが知られている出力から JComponent.paintImmediately()はJava Swingでどのように動作しますか?
public class PaintingDemo {
public static void main(String[] args) {
final JFrame frame = new JFrame();
final JPanel p = new MyPanel();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.add(p, BorderLayout.CENTER);
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
new Thread("MyThread") {
public void run() {
while (true) {
// Below statements are important to show the difference
p.repaint();
p.paintImmediately(p.getBounds());
try {
Thread.sleep(1000);
} catch(Exception e) {}
}
}
}.start();
}
}
class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
System.out.println("paint() called in "+ Thread.currentThread().getName());
super.paint(g);
}
}
。しかし、paintImmediately()の場合、ペイントはそれが呼び出された同じスレッドで行われます。
EDTがコンポーネントの状態を変更し、別のスレッド(paintImmediately()が呼び出された)が同じコンポーネントをペイントしている場合を考えてみましょう。
は私の質問:paintImmediately()の場合 は、どのようにイベントディスパッチャスレッド(EDT)と他のスレッド間の同期が処理されますか?これはJComponent
ない場合を除き、あなたはスタックトレースが示唆するようpaint(Graphics)
を呼び出して終了_paintImmediately()
を呼び出してしまう、だから、
Component c = this;
Component parent;
if(!isShowing()) {
return;
}
JComponent paintingOigin = SwingUtilities.getPaintingOrigin(this);
if (paintingOigin != null) {
Rectangle rectangle = SwingUtilities.convertRectangle(
c, new Rectangle(x, y, w, h), paintingOigin);
paintingOigin.paintImmediately(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
return;
}
while(!c.isOpaque()) {
parent = c.getParent();
if(parent != null) {
x += c.getX();
y += c.getY();
c = parent;
} else {
break;
}
if(!(c instanceof JComponent)) {
break;
}
}
if(c instanceof JComponent) {
((JComponent)c)._paintImmediately(x,y,w,h);
} else {
c.repaint(x,y,w,h);
}
:あなたはpaintImmediatelyを呼び出すとき
+1あなたはそれを釘付けにしました。 'JComponent'ドキュメントがなぜ' paintImmediately() 'と' repaint(..) 'を参照しているのかというだけでは不思議です。あなたのスニペットで、 'JComponent'の' paint(..) 'をオーバーライドすることは決してありません。どうして' paintComponent'を使用しなかったのですか(まだ結果を再現しているようです)?そしてもう一つの疑問はなぜ 'sleep(int milis) 'を増やして衝突を増加させないのでしょうか?また、EDT以外のスレッドから 'paintImmediately'を呼び出すのはなぜですか(なぜならEDTで呼び出されるのはnullが発生しないためです)。 –
自分自身で試してみて、あなたの研究を共有してくれてありがとう@Guillaume。私はpaintImmediately()を使用する理由はそれほど多くないことに同意しますが、私は単にそれがどのように機能するのかを理解しようとしていました。 javadocはこう言っています。 "このメソッドは、現在のイベントがディスパッチされている間にディスプレイを更新する必要がある場合に便利です。"また、このメソッドは公開されており、その警告についてはどこにも言及されていない警告は絶対にありません。少なくともjavadocは誤解を招きます。今私はpaintImmediately()がEDT内で呼び出される必要があり、repaint()とは異なりスレッドセーフではないことを理解しています。 – Learner
@DavidKroukamp 'paintComponent'ではなく' paint'をオーバーライドする正当な理由はなく、 'paintImmediately'が最終的に' paint'を呼び出すのを見て、スタックコールの 'paintComponent'への追加呼び出しを追加することは不要でした観察された結果は同じままである。だから、情報から「ノイズ」を取り除くだけではなく、スニペットの前に述べたように、スイングを使う正しい方法を示していません。乾杯;-) –