为什么Java repaint()方法不起作用? [英] why Java repaint() method not working?

查看:178
本文介绍了为什么Java repaint()方法不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码是涉及图像的非常简单的测试. 每当我向System.in发送"a"时,它应该重新绘制图像,而当我发送"q"时,它应该退出程序.

The code below is a very simple test which involves an image. It should repaint an image whenever I send "a" to System.in and it should exit the program whenever I send "q".

问题在于只有出口有效: 永远不会调用paint()方法,我也不为什么.

The problem is that only the exit works: the method paint() is never called, and I don't why.

我检查了对"super.paint()"的调用,尝试用paintCompoenent(Graphics g)替换paint(Graphics g),但似乎无济于事:根本没有调用.

I checked for the call to "super.paint()", tried replacing paint(Graphics g) with paintCompoenent(Graphics g) but nothing seems to work: simply there's no call.

是否涉及到main()中的扫描仪的问题?

Is the problem involving the Scanner in main()?

程序中的路径与我使用的路径不同,并且第一个画图正确,因此问题不应该存在.

The path in the program is not the same I used, and the first paint is right, so the problem shouldn't be there.

注意,如果有用,我正在使用Eclipse Oxygen和Java9 SE

NB if it's useful, I'm using Eclipse Oxygen and Java9 SE

谢谢大家!

代码粘贴:

public class TestImagePanel extends JPanel {

    private BufferedImage image;
    private int xpos = 0;
    private int ypos = 0;
    private String _imagePath = "//myFolder//image.png";

    public TestImagePanel() {
        try {
            image = ImageIO.read(new File(_imagePath));
        } catch (IOException ex) {}
    }

    public void paint(Graphics g) {
        super.paint(g);
        System.out.println("painting LOG");
        g.drawImage(image, this.xpos++, this.ypos++, this);
    }

    public void update(String a) {
        System.out.print("Receiving:" + a + "---" + xpos + ":" + ypos);
        if (a.equals("a"))
            repaint();
        else if (a.equals("q")) {
            System.out.println("LOGOUT");
            System.exit(0);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("test");
        TestImagePanel testimg = new TestImagePanel();
        frame.add(new TestImagePanel());
        frame.setSize(new Dimension(600, 600));
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Scanner in = new Scanner(System.in);
        while (true)
            testimg.update( in .next());
    }
}

推荐答案

因此,有一些错误...

So, there's a few mistakes...

让我们从这里开始...

Let's start here...

JFrame frame = new JFrame("test");
TestImagePanel testimg = new TestImagePanel();
frame.add(new TestImagePanel());

//...

Scanner in = new Scanner(System.in);
while (true)
    testimg.update( in .next());

您要创建两个TestImagePanel实例,并且只更新屏幕上不存在的实例

You're creating two instances of TestImagePanel and you're only updating the instance which is not on the screen

类似...

JFrame frame = new JFrame("test");
TestImagePanel testimg = new TestImagePanel();
frame.add(testimg);

//...

Scanner in = new Scanner(System.in);
while (true)
    testimg.update( in .next());

会有所帮助.

下一步...

public void paint(Graphics g) {
    super.paint(g);
    System.out.println("painting LOG");
    g.drawImage(image, this.xpos++, this.ypos++, this);
}

好的,您应该避免覆盖paint,通常建议您覆盖paintComponent.

Okay, you should avoid overriding paint, as a general preference it's recommend to override paintComponent instead.

由于绘画可能出于多种原因在任何时候发生,因此您永远不要从绘画方法内部更新或修改UI的状态,绘画是用于绘画当前状态

Because painting can occur at any time for any number of reasons, you should never update or modify the state of the UI from within paint methods, painting is for painting the current state

所以,它应该更像是...

So, it should be something more like...

protected void paintComponent(Graphics g) {
    super.paint(g);
    g.drawImage(image, this.xpos, this.ypos, this);
}

好的,那么,如何更新xposypos值?在您的情况下,update方法可能是显而易见的选择....

Okay, so, then how do we update the xpos and ypos values? In your case, the update method is probably the obvious choice....

public void update(String a) {
    xpos++;
    ypos++;
    System.out.print("Receiving:" + a + "---" + xpos + ":" + ypos);
    if (a.equals("a"))
        repaint();
    else if (a.equals("q")) {
        System.out.println("LOGOUT");
        System.exit(0);
    }
}

现在,这引起了一个问题. paintComponent方法需要xposypos,这意味着这些值不应在事件调度线程的上下文之外进行更新

Now, this raises an issue. xpos and ypos are needed by the paintComponent method, this means that these values should not be updated outside the context of the Event Dispatching Thread

一个简单的解决方法可能是做类似的事情...

A simple fix might be to do something like...

public void update(String a) {
    if (!EventQueue.isDispatchThread()) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                update(a);
            }
        });
    }
    xpos++;
    ypos++;
    System.out.print("Receiving:" + a + "---" + xpos + ":" + ypos);
    if (a.equals("a")) {
        repaint();
    } else if (a.equals("q")) {
        System.out.println("LOGOUT");
        System.exit(0);
    }
}

这确保update方法的内容在EDT的上下文中执行.

This ensures that the contents of the update method is executed within the context of the EDT.

恕我直言,这有点混乱.更好的解决方案是使用SwingWorker

This, IMHO, is kind of a mess. A better solution would be to use a SwingWorker

SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
    @Override
    protected Void doInBackground() throws Exception {
        Scanner in = new Scanner(System.in);
        while (true) {
            publish(in.next());
        }
    }

    @Override
    protected void process(List<String> chunks) {
        for (String text : chunks) {
            testimg.update(text);
        }
    }

};

这有助于我们将更新内容放入EDT.

This takes care of putting the updates onto the EDT for us.

这将生成一个类似于以下内容的解决方案...

This generates a solution which looks something like this...

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

public class TestImagePanel extends JPanel {

    private BufferedImage image;
    private int xpos = 0;
    private int ypos = 0;
    private String _imagePath = "//myFolder//image.png";

    public TestImagePanel() {
        try {
            image = ImageIO.read(new File(_imagePath));
        } catch (IOException ex) {
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println("painting LOG");
        g.drawImage(image, this.xpos, this.ypos, this);
    }

    public void update(String a) {
        System.out.print("Receiving:" + a + "---" + xpos + ":" + ypos);
        if (a.equals("a")) {
            xpos++;
            ypos++;
            repaint();
        } else if (a.equals("q")) {
            System.out.println("LOGOUT");
            System.exit(0);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("test");
        TestImagePanel testimg = new TestImagePanel();
        frame.add(new TestImagePanel());
        frame.setSize(new Dimension(600, 600));
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                Scanner in = new Scanner(System.in);
                while (true) {
                    publish(in.next());
                }
            }

            @Override
            protected void process(List<String> chunks) {
                for (String text : chunks) {
                    testimg.update(text);
                }
            }

        };

    }
}

现在,问题是,为什么要在GUI程序中从控制台获取输入?您应该通过GUI输入数据吗?以上可能是从文件或其他自动源中读取内容的很好的解决方案,但应避免在用户输入时使用……这不是GUI的工作原理.

Now, the question is, why are you taking input from the console in a GUI program? You should be inputing data via the GUI? The above might be a good solution for reading content from a file or other automated source, but should be avoid for user input ... this isn't how GUIs are suppose to work.

这篇关于为什么Java repaint()方法不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆