【问题标题】:How to paint another object instead of repaint() JPanel如何绘制另一个对象而不是 repaint() JPanel
【发布时间】:2017-09-21 14:44:51
【问题描述】:

我有一个 JFrame,我在其中使用 3 个线程打印 3 个对象:
Thread-1) 打印圆圈
Thread-2) 打印正方形
Thread-3) 打印三角形
问题是我需要一遍又一遍地打印新对象,而不仅仅是重新绘制它们。但是我每个线程的run()函数都无法触及类的Overrideded方法paintComponent(Graphics g)的Graphics g变量。我只能在 run() 函数中使用 repaint()。
这就是我所拥有的:(repaint() 使用的方法https://prnt.sc/gnxz6iM
这就是我想要的(没有 paintImmediately() 方法的那些方形边框):https://prnt.sc/gny1qx

package tarefa03;

import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.Random;
import javax.swing.OverlayLayout;


public class FigurePlacer extends JPanel implements Runnable{
    final int width = 700;
    final int height = 700;
    int x_pos = 0;
    int y_pos = 0;
    int x_width = 50;
    int y_height = 50;
    String figure;

    public FigurePlacer(String str){
        figure = str;
        randomCoord();
        setOpaque(false);
        setBounds(0, 0, width, height);
        Thread th = new Thread (this);
        th.start();
    }

    private void randomCoord(){
        Random random = new Random();
        x_pos = random.nextInt(width);
        y_pos = random.nextInt(height);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        switch (figure){       
            case "circle":
            g2.setColor(Color.BLUE);
            g2.fillOval(x_pos, y_pos, x_width, y_height);
            break;

            case "square":     
            g2.setColor(Color.GREEN);
            g2.fillRect(x_pos, y_pos, x_width, y_height);
            break;

            case "triangle":
            g2.setColor(Color.ORANGE);
            int xpoints[] = {x_pos, x_pos+25, x_pos+50};
            int ypoints[] = {y_pos, y_pos+50, y_pos};
            g2.fillPolygon(xpoints,ypoints,3);
        }
    }

    @Override
    public void run(){
        while (true){
            randomCoord();
            this.paintImmediately(x_pos, y_pos, x_width, y_height);
            try{
                Thread.sleep (200);
            }
            catch (InterruptedException ex){}
        }
    }  

}

【问题讨论】:

  • 如果您删除 super.paintComponent(g); 会发生什么?
  • @Berger 它可能会破坏油漆链......所以不建议......
  • 为了获得更好的帮助,尽快发布有效的minimal reproducible example,我可以在快速查看代码中看到:1) 使用setBounds() = 使用null-layout (Frowned upon)。 2) 与其自己创建线程,不如使用 3 Swing Timers?
  • 如果您想一遍又一遍地绘制它们,您可以: A) 将它们保存到列表中,迭代列表并在其上绘制每个项目。 B) 将它们绘制到BufferedImage,然后显示该图像...使用哪一个,取决于您的需要...
  • 没有repaint(...)-ing 面板就没有安全的绘图方式。以这种方式挥杆并不安全。

标签: java multithreading swing


【解决方案1】:

您的渲染没有表明它的绘图例程不是不透明的。

在绘制某物时,setOpaque(...) 方法会提示渲染线程是否可以直接设置背景像素,或者必须检查透明度并与现有像素值混合。

请注意,您还必须在颜色中设置透明度。缺少这样的东西意味着您的混合支持可能已打开,但您绘制了不透明的颜色。

另外,Swing 不是多线程安全的。它使用私有线程进行光栅化和 UI 更新。任何“多线程”解决方案都需要将所有 UI 更新分派到此绘图线程。否则,您将无法获得您想要的结果(因为该渲染线程已集成到核心 OS 绘图例程中,并且专门为支持 AWT、Swing 和其他技术而编写。

这意味着即使是像呈现 GUI 框架这样的小事情也需要“调度”。如果您有任务需要在主 Java 线程和绘图线程之间进行协调,请参阅 SwingWorker;如果协调不是那么精细,请参阅 SwingUtilites.invokeAndWait(...) / SwingUtilites.invokeLater(...)。

是的,你可以尝试从主线程做一些事情(就像你做的那样)。有时它几乎可以工作,但通常它不会正常工作,并且随着时间的推移不会继续正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    相关资源
    最近更新 更多