Обновление значка изображения в JLabel в Swing?Использование revalidate () и repaint (), но не работает - PullRequest
0 голосов
/ 23 июня 2018

Хорошо, я только привыкаю к ​​ООП и сейчас только учусь свингу.Я делаю простое приложение, которое представляет собой сетку 2х2 из 4 изображений (X, O, Квадрат и Треугольник), и щелкаю любое из них, меняя форму цвета на синий.

Я не могу получить егохотя переключитесь на новое изображение, и я думаю, что оно как-то связано с чем-то фундаментальным для моей программы.

Не возражаете ли вы взглянуть?

Класс JFrame:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import javax.swing.JPanel;

public class Frame1 {

    public JFrame frame;

        Frame1 window = new Frame1();
        window.frame.setVisible(true);

    }

    public Frame1() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 900, 900);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        Squares x = new Squares("images\\black-X.png", "images\\blue-X.png", 0, 0, 450, 450, "x");
        Squares o = new Squares("images\\black-O.png", "images\\blue-O.png", 450, 0, 450, 450, "o");
        Squares sq = new Squares("images\\black-sq.png", "images\\blue-sq.png", 0, 425, 450, 450, "sq");
        Squares tri = new Squares("images\\black-tri.png", "images\\blue-tri.png", 450, 410, 450, 450, "tri");


        frame.getContentPane().add(x.getLabel());
        frame.getContentPane().add(o.getLabel());
        frame.getContentPane().add(sq.getLabel());
        frame.getContentPane().add(tri.getLabel());
    }


}

Mouselistener Class:

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class clickListener implements MouseListener{

    Squares ob = new Squares();

    public clickListener(Squares newSquare) {
        ob = newSquare;
    }

    public void mouseClicked(MouseEvent e) {
        ob.changePic();
    }

}

А потом класс объекта, который я создаю для каждого изображения

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

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Squares {

    String pic1, pic2, name;
    int x, y, width, height;

    JPanel panel = new JPanel();
    JLabel label = new JLabel();

    public Squares() {
        ;
    }

    public Squares(String pic1, String pic2, int x, int y, int width, int height, String name) {
        this.pic1 = pic1;
        this.pic2 = pic2;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.name = name;

        BufferedImage myPic1 = null;

        try {
            myPic1 = ImageIO.read(new File(pic1));

        } catch (IOException ex) {System.out.println("error in image upload");}

        /*
        panel.setBounds(x, y, width, height);
        panel.add(new JLabel(new ImageIcon(myPic1)));   
        panel.addMouseListener(new clickListener(this));
        */

        label = new JLabel(new ImageIcon(myPic1));
        label.setBounds(x, y, width, height);
        label.addMouseListener(new clickListener(this));
    }

    public JLabel getLabel() {
        return label;
    }

    public String getName() {
        return this.name;
    }

    public void changePic() {
        JOptionPane.showMessageDialog(null, "change pic reached for " + this.name);
        BufferedImage myPic2 = null;
        try {myPic2 = ImageIO.read(new File(pic2));}
        catch(IOException ex) {System.out.println("error in image upload");}
        label = new JLabel(new ImageIcon(myPic2));
        label.setBounds(x, y, width, height);
        label.repaint();
        label.revalidate();
    }
}

Я изначально использовал JPanels, которые содержали каждый JLabel, но я избавился от нихвсе для упрощения вещей.

Так что да, любые предложения приветствуются.Спасибо!

1 Ответ

0 голосов
/ 24 июня 2018

Таким образом, проблема "ядра" заключается в вашем changePic методе

public void changePic() {
    JOptionPane.showMessageDialog(null, "change pic reached for " + this.name);
    BufferedImage myPic2 = null;
    try {
        myPic2 = ImageIO.read(new File(pic2));
    } catch (IOException ex) {
        System.out.println("error in image upload");
    }
    label = new JLabel(new ImageIcon(myPic2));
    label.setBounds(x, y, width, height);
    label.repaint();
    label.revalidate();
}

В этом методе вы создаете новый экземпляр JLabel, но он никогда не добавляется ни в один контейнер, который присоединен кэкран, поэтому он никогда не будет отображаться.

Простое решение состоит в том, чтобы просто изменить свойство icon существующего экземпляра JLabel

public void changePic() {
    JOptionPane.showMessageDialog(null, "change pic reached for " + this.name);
    BufferedImage myPic2 = null;
    try {
        myPic2 = ImageIO.read(new File(pic2));
    } catch (IOException ex) {
        System.out.println("error in image upload");
    }
    label.setIcon(new ImageIcon(pic2));
}

Наблюдения ...

Проходя по коду, я нашел несколько вещей, которые можно было бы сделать лучше.

  • (несмотря на его название) Frame1 не несет ответственности за управление основнымРамка.Основная функциональность будет лучше управляться через другой контейнер, это разъединит компонент и сделает его более гибким и многократно используемым в долгосрочной перспективе - вам также не нужно включать сложность управления кадрами в компоненты и другие обязанности.
  • Вам следует избегать null макетов.Более простым решением было бы использовать GridLayout, поскольку у предоставленной вами реализации есть проблемы с макетом
  • Squares не нужно знать местоположение или размер, который хочет родительский контейнер - это не совсемРешение родительский контейнер должен принимать непосредственно.Вместо этого Squares должен предоставлять подсказки по размерам обратно в родительский контейнер, чтобы он мог принимать лучшие решения о том, как расположить все дочерние компоненты.JLabel способен предоставить эту информацию сам.
  • Возможно, Squares должно расширяться от JLabel - это чисто одно из простоты.JLabel - идеальное место для отображения изображений, так что это хороший выбор для работы, но обертывание вокруг него класса просто делает его управление несколько более громоздким и в этом случае добавляет очень мало пользы.Есть соглашение для составления над наследованием, но в этом случае, я не уверен, что это добавит больше значения
  • ClickListener не нужно создавать экземпляр Squares, этотолько конструктор требует от любого вызывающего абонента передать ему экземпляр Squares в любом случае
  • Из-за своей основной функциональности Squares должен завершиться неудачей, если какое-либо из изображений не может быть загружено, это сделает его намногопроще диагностировать эти проблемы, чем продолжать выполнение программы в «неисправном» состоянии

IMHO

Пример

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Game {

    public static void main(String[] args) {
        new Game();
    }

    public Game() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new GamePane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class GamePane extends JPanel {

        public GamePane() throws IOException {
            initialize();

        }

        private void initialize() throws IOException {
            Square x = new Square("images\\black-X.png", "images\\blue-X.png", "x");
            Square o = new Square("images\\black-O.png", "images\\blue-O.png", "o");
            Square sq = new Square("images\\black-sq.png", "images\\blue-sq.png", "sq");
            Square tri = new Square("images\\black-tri.png", "images\\blue-tri.png", "tri");

            setLayout(new GridLayout(2, 2));

            add(x);
            add(o);
            add(sq);
            add(tri);
        }

    }

    public class ClickListener extends MouseAdapter {

        private Square ob;

        public ClickListener(Square newSquare) {
            ob = newSquare;
        }

        public void mouseClicked(MouseEvent e) {
            ob.changePic();
        }

    }

    public class Square extends JLabel {

        String name;
        private BufferedImage myPic1, myPic2;

        public Square(String pic1, String pic2, String name) throws IOException {
            this.name = name;

            myPic1 = ImageIO.read(new File(pic1));
            myPic2 = ImageIO.read(new File(pic2));

            setIcon(new ImageIcon(myPic1));
            addMouseListener(new ClickListener(this));
        }

        public String getName() {
            return this.name;
        }

        public void changePic() {
            setIcon(new ImageIcon(myPic2));
        }
    }
}
...