JComponent.paintImmediately()如何在Java Swing中运行?

前端之家收集整理的这篇文章主要介绍了JComponent.paintImmediately()如何在Java Swing中运行?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我的理解:
与JComponent.repaint()中Swing调用的大多数组件/操作不同,线程安全即使是从另一个线程(即不是从EDT)进行重新绘制请求,所以实际绘画仅在EDT中发生.以下代码片段演示了这一点.
  1. public class PaintingDemo {
  2.  
  3. public static void main(String[] args) {
  4. final JFrame frame = new JFrame();
  5. final JPanel p = new MyPanel();
  6. SwingUtilities.invokeLater(new Runnable() {
  7. @Override
  8. public void run() {
  9. frame.add(p,BorderLayout.CENTER);
  10. frame.setSize(200,200);
  11. frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
  12. frame.setVisible(true);
  13. }
  14. });
  15. new Thread("MyThread") {
  16. public void run() {
  17. while (true) {
  18. // Below statements are important to show the difference
  19. p.repaint();
  20. p.paintImmediately(p.getBounds());
  21. try {
  22. Thread.sleep(1000);
  23. } catch(Exception e) {}
  24. }
  25. }
  26. }.start();
  27. }
  28.  
  29. }
  30.  
  31. class MyPanel extends JPanel {
  32. @Override
  33. public void paint(Graphics g) {
  34. System.out.println("paint() called in "+ Thread.currentThread().getName());
  35. super.paint(g);
  36. }
  37. }

输出中可以看出,在调用repaint()时,在EDT中完成绘制,而不管调用哪个线程 – 所以没有问题.但是,在paintImmediately()的情况下 – 绘画发生在调用它的同一个线程中.

考虑一个情况是,EDT正在更改组件的状态,另一个线程(从中调用paintImmediately())正在绘制相同的组件.

我的问题:
在paintImmediately()的情况下,Event Dispatcher Thread(EDT)和其他线程之间的同步处理如何?

解决方法

据我了解,当您调用paintImmediately时,您调用以下代码
  1. Component c = this;
  2. Component parent;
  3.  
  4. if(!isShowing()) {
  5. return;
  6. }
  7.  
  8. JComponent paintingOigin = SwingUtilities.getPaintingOrigin(this);
  9. if (paintingOigin != null) {
  10. Rectangle rectangle = SwingUtilities.convertRectangle(
  11. c,new Rectangle(x,y,w,h),paintingOigin);
  12. paintingOigin.paintImmediately(rectangle.x,rectangle.y,rectangle.width,rectangle.height);
  13. return;
  14. }
  15.  
  16. while(!c.isOpaque()) {
  17. parent = c.getParent();
  18. if(parent != null) {
  19. x += c.getX();
  20. y += c.getY();
  21. c = parent;
  22. } else {
  23. break;
  24. }
  25.  
  26. if(!(c instanceof JComponent)) {
  27. break;
  28. }
  29. }
  30. if(c instanceof JComponent) {
  31. ((JComponent)c)._paintImmediately(x,h);
  32. } else {
  33. c.repaint(x,h);
  34. }

所以,除非这不是一个JComponent,否则你最终会调用_paintImmediately(),最后调用paint(Graphics),建议下面的栈跟踪(从我将在这篇文章结尾发贴的一段代码获取):

  1. Thread [pool-1-thread-1] (Suspended)
  2. TestPaint$1.paint(Graphics) line: 23
  3. TestPaint$1(JComponent).paintToOffscreen(Graphics,int,int) line: 5221
  4. RepaintManager$PaintManager.paintDoubleBuffered(JComponent,Image,Graphics,int) line: 1482
  5. RepaintManager$PaintManager.paint(JComponent,JComponent,int) line: 1413
  6. RepaintManager.paint(JComponent,int) line: 1206
  7. TestPaint$1(JComponent)._paintImmediately(int,int) line: 5169
  8. TestPaint$1(JComponent).paintImmediately(int,int) line: 4980
  9. TestPaint$1(JComponent).paintImmediately(Rectangle) line: 4992
  10. TestPaint$3.run() line: 50
  11. ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1110
  12. ThreadPoolExecutor$Worker.run() line: 603
  13. Thread.run() line: 722

但是如果您尝试同时调用repaint()(从另一个线程),您会看到它们同时运行(我尝试使用调试器执行代码并绘画从未停止在另一个线程中发生)似乎在Java代码级别,没有太多同步(至少我找不到任何东西).所以如果你最后在EDT中修改组件状态,我相信结果是不可预测的,你应该一定要避免这种情况.

为了说明我的观点,我尝试在paint方法修改一个变量的状态,添加一个睡眠以增加2个线程(EDT和另一个线程)之间的冲突风险,并且它看起来似乎没有两者之间的同步线程(System.err.println()不时输出为null).

现在我想知道为什么你需要立即执行一个paint.除非你阻止EDT,否则没有太多有效的理由来执行这样的事情.

以下是我用来测试这些东西的代码(非常接近问题中的一个).代码只是为了尝试了解发生了什么,而不是展示如何执行正确的绘画或任何好的Swing练习.

  1. import java.awt.Color;
  2. import java.awt.Graphics;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. import java.util.Random;
  6. import java.util.concurrent.Executors;
  7.  
  8. import javax.swing.JFrame;
  9. import javax.swing.JPanel;
  10. import javax.swing.SwingUtilities;
  11. import javax.swing.Timer;
  12.  
  13. public class TestPaint {
  14.  
  15. protected void initUI() {
  16. JFrame frame = new JFrame();
  17. frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
  18. frame.setTitle(TestPaint.class.getSimpleName());
  19. final Random rand = new Random();
  20. final JPanel comp = new JPanel() {
  21. private String value;
  22.  
  23. @Override
  24. public void paint(Graphics g) {
  25. value = "hello";
  26. super.paint(g);
  27. try {
  28. Thread.sleep(20);
  29. } catch (InterruptedException e) {
  30. // TODO Auto-generated catch block
  31. e.printStackTrace();
  32. }
  33. g.setColor(new Color(rand.nextInt(256),rand.nextInt(256),rand.nextInt(256)));
  34. g.fillRect(0,getWidth(),getHeight());
  35. if (SwingUtilities.isEventDispatchThread()) {
  36. System.err.println("Painting in the EDT " + getValue());
  37. } else {
  38. System.err.println("Not painting in EDT " + getValue());
  39. }
  40. value = null;
  41. }
  42.  
  43. public String getValue() {
  44. return value;
  45. }
  46. };
  47. frame.add(comp);
  48. frame.setSize(400,400);
  49. frame.setLocationRelativeTo(null);
  50. frame.setVisible(true);
  51. Timer t = new Timer(1,new ActionListener() {
  52.  
  53. @Override
  54. public void actionPerformed(ActionEvent e) {
  55. comp.repaint();
  56. }
  57. });
  58. t.start();
  59. Executors.newSingleThreadExecutor().execute(new Runnable() {
  60.  
  61. @Override
  62. public void run() {
  63. while (true) {
  64. comp.paintImmediately(comp.getBounds());
  65. }
  66. }
  67. });
  68. }
  69.  
  70. public static void main(String[] args) {
  71. SwingUtilities.invokeLater(new Runnable() {
  72. @Override
  73. public void run() {
  74. new TestPaint().initUI();
  75. }
  76. });
  77. }
  78.  
  79. }

猜你在找的Java相关文章