Обновление панели JLabel при каждом обновлении фрейма

#java #swing

#java #swing

Вопрос:

Как я могу обновить JLabel Count #0 до Count #1 , как продолжалось, на верхней панели во фрейме?

Изначально это так, Count #0 и по мере дальнейшего выполнения операции оно меняется на Count #1 .

ВЫВОД: Здесь это отображается, Count #0 но это должно быть Count #2 так, как серое поле находится на втором уровне, аналогично здесь оно должно отображаться Count #5 , так как оно находится на пятом уровне сверху.

 import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

class Count {
    private int num;
    
    public Count() {
        this.num = 1;
    }
    
    // Generate Next Number
    public void generate(int currentNumber) {
        this.num = currentNumber;
        this.num  = 1;
    }
    
    public int getNumber() {
        return this.num;
    }
}

class Panel extends JPanel {
    private final BufferedImage image;
    private Count count;
    
    public Panel() {
        this.image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
        this.count = new Count();
        Timer timer = new Timer(0, ae -> createImage(image));
        timer.setDelay(1000);
        timer.start();
    }
    
    public void createImage(BufferedImage image) {
        Graphics g = image.getGraphics();
        
        int number = this.count.getNumber();
        
        // Set field on frame which will be added to bottomPanel
        for (int i = 0; i < (number * 20); i  ) {
            for (int j = 0; j < (number * 20); j  ) {
                g.setColor(Color.GRAY);
                g.fillRect(i, j, 20, 20);
                g.setColor(Color.GREEN);
                g.drawRect(i, j, 20, 20);
            }
        }
        
        // Generating next number
        this.count.generate(number);
        repaint();
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, null);
    }
}

class GUI extends JFrame {
    private JPanel topPanel;
    private JPanel bottomPanel;
    
    public GUI() {
        topPanel = new JPanel();
        bottomPanel = new JPanel();
        
        // Setting topPanel and Adding Label to topPanel
        topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.PAGE_AXIS));
        updateLabel(0);
        
        // Instructions for bottomPanel
        Panel panel = new Panel();
        panel.setPreferredSize(new Dimension(300, 300));
        
        // Adding the instructions to bottomPanel
        bottomPanel.add(panel);

        // Adding topPanel and bottomPanel to Frame
        add(topPanel, BorderLayout.PAGE_START);
        add(bottomPanel, BorderLayout.CENTER);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        pack();
    }
    
    public void updateLabel(int number) {
        // Label - 1
        JLabel countLabel = new JLabel("CountLabel");
        countLabel.setText("   Count #"   number);
        countLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 14));
        countLabel.setBounds(10, 5, 300, 20);
        
        topPanel.add(countLabel);
    }
}

public class NumberPresentation {
    public static void main(String[] args) {
        new GUI().setVisible(true);
    }
}
  

Итак, как я должен начать работать, чтобы JLabel в TopPanel продолжал обновляться каждый раз, когда Count присваивается generate() другой номер, и generate() вызывается в функции Panel класса createImage() ?

Спасибо.

PS: Анимация нижней части хорошая, я просто хочу знать, как я могу работать с JLabel, чтобы обновлять ее каждый раз.

Ответ №1:

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

Идея состоит в том, чтобы добавить onUpdate метод в ваш класс Panel, который вызывается при каждом обновлении панели. А затем, чтобы определить, какое действие выполняется при создании панели.

Для этого вам сначала нужно будет объявить абстрактный класс или интерфейс с нужными вам методами, я выбираю общие имена, но не стесняйтесь настраивать

 interface Callback {
    public void action(int v);
}
  

Теперь мы можем передать метод declare и передать метод action, который принимает целое число в любой класс, вам просто нужно добавить поле обратного вызова :

 class Panel extends JPanel {
    private final BufferedImage image;
    private Count count;
    private Callback onUpdate;

    public void setOnUpdateAction(Callback action) {
        this.onUpdate = action;
    }
  

Вы можете выбрать, куда вызывать onUpdate, я сделал это после генерации следующего номера

 // Generating next number
this.count.generate(number);
onUpdate.action(this.count.getNumber());
repaint();
  

Теперь ваш Panel класс готов.

Теперь, после создания вашей панели, просто вызовите setOnUpdateAction

 panel.setOnUpdateAction(new Callback() {
    public void action(int v) {
        countLabel.setText("   Count #"   v);
    }
});
  

Поскольку существует только один метод и одна инструкция, вы можете использовать более короткий синтаксис лямбда, аналогичный тому, который вы использовали в таймере

 panel.setOnUpdateAction(v -> countLabel.setText("   Count #"   v));
  

(Мне пришлось сделать countLabel полем для доступа к нему в графическом интерфейсе.)

И вот оно!

введите описание изображения здесь

Вот полный измененный код :

 import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

class Count {
    private int num;

    public Count() {
        this.num = 1;
    }

    // Generate Next Number
    public void generate(int currentNumber) {
        this.num = currentNumber;
        this.num  = 1;
    }

    public int getNumber() {
        return this.num;
    }
}

interface Callback {
    public void action(int v);
}

class Panel extends JPanel {
    private final BufferedImage image;
    private Count count;
    private Callback onUpdate;


    public void setOnUpdateAction(Callback action) {
        this.onUpdate = action;
    }

    public Panel() {
        this.image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
        this.count = new Count();
        Timer timer = new Timer(0, ae -> createImage(image));
        timer.setDelay(1000);
        timer.start();
    }

    public void createImage(BufferedImage image) {
        Graphics g = image.getGraphics();

        int number = this.count.getNumber();

        // Set field on frame which will be added to bottomPanel
        for (int i = 0; i < (number * 20); i  ) {
            for (int j = 0; j < (number * 20); j  ) {
                g.setColor(Color.GRAY);
                g.fillRect(i, j, 20, 20);
                g.setColor(Color.GREEN);
                g.drawRect(i, j, 20, 20);
            }
        }

        // Generating next number
        this.count.generate(number);
        onUpdate.action(this.count.getNumber());
        repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, null);
    }
}

class GUI extends JFrame {
    private JPanel topPanel;
    private JPanel bottomPanel;
    private JLabel countLabel;  // Made it a field to use after being created

    public GUI() {
        topPanel = new JPanel();
        bottomPanel = new JPanel();

        // Setting topPanel and Adding Label to topPanel
        topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.PAGE_AXIS));
        updateLabel(0);

        // Instructions for bottomPanel
        Panel panel = new Panel();
        panel.setPreferredSize(new Dimension(300, 300));

        panel.setOnUpdateAction(new Callback() {
            public void action(int v) {
                countLabel.setText("   Count #"   v);
            }
        });

        // You can also use this lambda syntax ( since Callback has only 1 method to implement )
        // panel.setOnUpdateAction(v -> countLabel.setText("   Count #"   v));


        // Adding the instructions to bottomPanel
        bottomPanel.add(panel);

        // Adding topPanel and bottomPanel to Frame
        add(topPanel, BorderLayout.PAGE_START);
        add(bottomPanel, BorderLayout.CENTER);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        pack();
    }

    public void updateLabel(int number) {
        // Label - 1
        countLabel = new JLabel("CountLabel");
        countLabel.setText("   Count #"   number);
        countLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 14));
        countLabel.setBounds(10, 5, 300, 20);

        topPanel.add(countLabel);
    }
}

public class NumberPresentation {
    public static void main(String[] args) {
        new GUI().setVisible(true);
    }
}