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