【问题标题】:Java Swing drawing wrong pictures due to delayJava Swing由于延迟绘制错误的图片
【发布时间】:2013-04-21 10:08:28
【问题描述】:

我是摇摆程序的新手,我在线程同步方面遇到了一些困难。

我正在尝试遍历一个数组并在每个索引处创建一个 JPanel 和一个 JFrame,并希望在每个面板上绘制一张图片。与存储在数组中的值相关的图片。 但是所有的框架/面板只保存最后一个数组条目的图片。我认为这是由于单独的 swing-Thread(?),但我不知道如何更改它。 你能帮帮我吗?

package help;

import java.awt.Graphics;
import java.awt.image.BufferedImage; 
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SwingSynchro{

private JPanel jPanel;
private JFrame jFrame;
int array[] = {1,2,3,4};
int current;
private BufferedImage image1;
private BufferedImage image2;
private BufferedImage image3;
private BufferedImage image4;

public SwingSynchro(){

    //try{
    //    image1 = ImageIO.read(new File("someFilePath1.png"));
    //    image2 = ImageIO.read(new File("someFilePath2.png"));
    //    image3 = ImageIO.read(new File("someFilePath3.png"));
    //    image4 = ImageIO.read(new File("someFilePath4.png"));
    //} catch(IOException e){
    //    e.printStackTrace();
    //    System.out.println("wrong file path");
    //}// try catch

    for(int i = 0 ; i < array.length ; i++){

        current = array[i];
            System.out.println("current Number: "+ current + " at array index:" +i);

            jPanel = new JPanel(){
                private static final long serialVersionUID = 6859593162185621113L;

                @Override
                protected void paintComponent(Graphics g){
                    super.paintComponent(g);

                    switch(current){
                        case 1:
                            System.out.println("case 1");
                            //g.drawImage(image1, 10, 10, getWidth() - 20, getHeight() - 20, this);
                            break;
                        case 2:
                            System.out.println("case 2");
                           // g.drawImage(image2, 20, 20, getWidth() - 40, getHeight() - 40, this);
                            break;
                        case 3:
                            System.out.println("case 3");
                            //g.drawImage(image3, 10, 10, getWidth() - 20, getHeight() - 20, this);
                            break;
                        case 4:
                            System.out.println("case 4");
                            //g.drawImage(image4, 10, 10, getWidth() - 20, getHeight() - 20, this);
                            break;
                        default:
                            System.out.println("RELEASE THE KRAKEN!");
                            break;
                    }// switch
                }// paintComponent()
            };// anonymous class(extends JPanel)


        jFrame = new JFrame(String.valueOf(current));
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setResizable(false);
        jFrame.getContentPane().add(jPanel);
        jFrame.setSize(200, 250);
        jFrame.setLocation(i * 203, 0);
        jFrame.setVisible(true);
    }
}
}

我注释掉了图片,因为控制台输出可以清楚地看到 drawImage 方法在整个 for 循环之后被调用。

编辑:看起来没有其他线程,但在那种情况下,我不明白为什么图纸(或案例陈述)会有这种延迟。你能解释一下为什么代码没有像往常一样执行吗?

这是输出:

current Number: 1 at array index:0
current Number: 2 at array index:1
current Number: 3 at array index:2
current Number: 4 at array index:3
case 4
case 4
case 4
case 4

【问题讨论】:

  • 您谈论的是多线程,但我在您的代码中完全看不到多线程。我错过了一些明显的东西吗?如果是这样,请给我看。你的Runnable呢?你在哪里创建这个你调用start()的所谓后台线程?
  • 我只是假设存在异步线程,因为这是我对该行为的唯一解释。
  • 您的假设不正确。当您直接或间接创建一个后台线程时,您将拥有后台线程,正如我上面提到的,我看不到您在哪里执行此操作。

标签: java swing synchronization


【解决方案1】:

您可以将 JPanel 设为内部类并使用字段来保存 current 变量的值,而不是将 JPanel 实例化为匿名类。

private static class CustomJPanel extends JPanel {
    private static final long serialVersionUID = 6859593162185621113L;
    private final int current;

    private CustomJPanel(int current) {
        this.current = current;
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);

        switch(current){
            case 1:
                System.out.println("case 1");
                //g.drawImage(image1, 10, 10, getWidth() - 20, getHeight() - 20, this);
                break;
            case 2:
                System.out.println("case 2");
                // g.drawImage(image2, 20, 20, getWidth() - 40, getHeight() - 40, this);
                break;
            case 3:
                System.out.println("case 3");
                //g.drawImage(image3, 10, 10, getWidth() - 20, getHeight() - 20, this);
                break;
            case 4:
                System.out.println("case 4");
                //g.drawImage(image4, 10, 10, getWidth() - 20, getHeight() - 20, this);
                break;
            default:
                System.out.println("RELEASE THE KRAKEN!");
                break;
        }// switch
    }// paintComponent()
}

然后将其实例化为

jPanel = new CustomJPanel(current);

这样,您可以确保它已被传递给 current 变量在 JPanel 被实例化时所具有的值。

【讨论】:

  • 当内部类超过 5 行时,我更喜欢编写匿名类。至于构造函数参数,我相信这是正确的(和线程安全的)方法,因为在 JPanel 实例化时确实需要 current 变量的值。请考虑接受答案。
  • @Enum:Zoltan 的编码没有任何问题,事实上这经常被普遍有效地使用(正如他所展示的那样)。 1+。
  • 谢谢大家,我在使用真正的代码时仍然遇到了一些问题(不过,对于这个例子来说,解决方案非常适合!)但是现在是凌晨 4 点,我现在需要睡觉 ;)
【解决方案2】:

Swing 是单线程的。如果您想实时查看 GUI 更新,请使用 Swing Timer

【讨论】:

    猜你喜欢
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多