pourquoi la méthode Java repaint () ne fonctionne pas?


Le code ci-dessous est un test très simple qui implique une image. Il devrait repeindre une image chaque fois que j'envoie "a" à System.in et il devrait quitter le programme chaque fois que j'envoie "q".

Le problème est que seule la sortie fonctionne: la méthode paint() n'est jamais appelée, et je ne sais pas pourquoi.

J'ai vérifié pour l'appel à super.paint ()", a essayé de remplacer paint(Graphics g) par paintCompoenent(Graphics g) mais rien ne semble fonctionner: il n'y a simplement pas d'appel.

Est le problème impliquant le scanner dans main ()?

Le chemin dans le programme n'est pas le même que j'ai utilisé, et la première peinture est correcte, donc le problème ne devrait pas être là.

NB si c'est utile, j'utilise Eclipse Oxygen et Java9 SE

Merci à tous!

Code coller:

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());
    }
}
Author: Francis Bartkowiak, 2018-03-28

2 answers

Donc, il y a quelques erreurs...

Commençons ici...

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());

Vous créez deux instances de TestImagePanel et vous ne mettez à jour que l'instance qui n'est pas à l'écran

Quelque chose comme...

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

//...

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

Aidera.

Suivant...

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

D'accord, vous devriez éviter de remplacer paint, comme préférence générale, il est recommandé de remplacer paintComponent à la place.

Parce que la peinture peut se produire à tout moment pour un certain nombre de raisons, vous devriez ne mettez jamais à jour ou ne modifiez jamais l'état de l'interface utilisateur à partir des méthodes paint, painting sert à peindre l'état actuel

Donc, cela devrait être quelque chose de plus...

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

Ok, alors, comment mettre à jour les valeurs xpos et ypos? Dans votre cas, la méthode update est probablement le choix évident....

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);
    }
}

Maintenant, cela soulève un problème. xpos et ypos sont nécessaires par la méthode paintComponent, cela signifie que ces valeurs ne doivent pas être mises à jour en dehors du contexte de l'événement Fil d'envoi

Une solution simple pourrait être de faire quelque chose comme...

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);
    }
}

Cela garantit que le contenu de la méthode update est exécuté dans le contexte de l'EDT.

Ceci, à mon HUMBLE avis, est une sorte de gâchis. Une meilleure solution serait d'utiliser un 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);
        }
    }

};

Cela prend soin de mettre les mises à jour sur l'EDT pour nous.

Cela génère une solution qui ressemble à ceci...

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);
                }
            }

        };

    }
}

Maintenant, la question est, pourquoi prenez-vous entrée de la console dans un programme GUI? Vous devriez entrer des données via l'interface graphique? Ce qui précède peut être une bonne solution pour lire du contenu à partir d'un fichier ou d'une autre source automatisée, mais devrait être évité pour l'entrée de l'utilisateur ... ce n'est pas comme ça que les interfaces graphiques sont supposées fonctionner.

 4
Author: MadProgrammer, 2018-03-29 04:06:57

Tout d'abord, vous ne devez pas remplacer la méthode paint (); vous shoul;d remplacer paintComponent() à la place.

Deuxièmement, vous ne le faites pas sur EventDispatchThread. Et même si vous l'étiez, mettre les mises à jour dans une boucle bloquera le thread de répartition des événements jusqu'à la fin de la boucle, ce qui n'entraînera qu'un seul repeint final.

 0
Author: FredK, 2018-03-28 19:58:43