英文:
Updating JLabel everytime Frame's panel is updated
问题
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class Count {
// ... (unchanged)
}
class Panel extends JPanel {
// ... (unchanged)
}
class GUI extends JFrame {
// ... (unchanged)
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);
// Update label text
if (topPanel.getComponentCount() > 0) {
topPanel.remove(0); // Remove existing label
}
topPanel.add(countLabel);
topPanel.revalidate();
topPanel.repaint();
}
}
public class NumberPresentation {
public static void main(String[] args) {
GUI gui = new GUI();
Count count = gui.panel.getCount(); // Get the Count instance from Panel
Timer labelUpdateTimer = new Timer(1000, e -> {
int currentNumber = count.getNumber();
gui.updateLabel(currentNumber);
count.generate(currentNumber);
});
labelUpdateTimer.start();
gui.setVisible(true);
}
}
Note: I've provided the necessary code snippets for updating the JLabel
in the topPanel
. Please integrate these snippets into your existing code structure. Additionally, it's important to keep in mind that the provided code is only part of the complete program, and you should ensure that the rest of your program remains consistent with these changes.
英文:
How can I update JLabel Count #0
to Count #1
as continued, at topPanel in Frame?
Initially it is Count #0
and as the operation performs further it changes to Count #1
.
OUTPUT: Here it is showing Count #0
but it should be Count #2
as the grey box is on second level, Similarly Here it should show Count #5
, as its on fifth level from top.
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);
}
}
So, how should I start working so that the JLabel in topPanel keeps updating every time Count
class generate()
another number, and generate()
is called in Panel
class's createImage()
function?
Thank You.
PS: The bottomPanel animation is good, I just want to know how I can work around with JLabel to update it everytime.
答案1
得分: 1
我建议采用回调导向的方法,这与JButton的addActionListener
工作方式非常相似。警告:如果滥用可能会变得混乱,但它可以保持初始类的分离。
思路是在你的面板类中添加一个onUpdate
方法,在面板更新时调用它。然后在创建面板时定义操作。
为此,你需要首先声明一个带有所需方法的抽象类或接口,我选择了通用名称,但你可以根据需要进行自定义。
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;
}
你可以自由选择何时调用onUpdate
,我在生成下一个数字后调用它:
// 生成下一个数字
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);
}
});
由于只有一个方法和一个指令,你可以使用与定时器中使用的Lambda语法类似的更短的Lambda语法:
panel.setOnUpdateAction(v -> countLabel.setText(" Count #" + v));
(我必须将countLabel
设置为字段,以便在GUI内部访问它。)
至此,你完成了!
这是完整修改后的代码:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class Count {
private int num;
public Count() {
this.num = 1;
}
// 生成下一个数字
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();
// 设置在框架上的字段,将添加到 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);
}
}
// 生成下一个数字
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; // 将其设置为字段,以便在创建后使用
public GUI() {
topPanel = new JPanel();
bottomPanel = new JPanel();
// 设置 topPanel 并添加 Label 到 topPanel
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.PAGE_AXIS));
updateLabel(0);
// bottomPanel 的指令
Panel panel = new Panel();
panel.setPreferredSize(new Dimension(300, 300));
panel.setOnUpdateAction(new Callback() {
public void action(int v) {
countLabel.setText(" Count #" + v);
}
});
// 你也可以使用这个 Lambda 语法(因为 Callback 只有一个方法要实现)
// panel.setOnUpdateAction(v -> countLabel.setText(" Count #" + v));
// 将指令添加到 bottomPanel
bottomPanel.add(panel);
// 将 topPanel 和 bottomPanel 添加到框架中
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);
}
}
英文:
I suggest a Callback oriented approach, this is very similar to how JButton's addActionListener
works. Warning it's a bit long and might get messy if you abuse it, but it keeps your initial classes separation intact.
The idea is to add an onUpdate
method to your Panel class that gets called every time the panel updates. And then to define what the action is when you create a panel.
For that, you will first need to declare an abstract class or interface with the methods you need, I choose generic names but feel free to customize
interface Callback {
public void action(int v);
}
We can now pass declare and pass an action method that takes an integer to any class, you just need to add a Callback field :
class Panel extends JPanel {
private final BufferedImage image;
private Count count;
private Callback onUpdate;
public void setOnUpdateAction(Callback action) {
this.onUpdate = action;
}
You're free to choose where to call onUpdate, I made it after the next number is generated
// Generating next number
this.count.generate(number);
onUpdate.action(this.count.getNumber());
repaint();
Your Panel
class is now ready.
Now after creating your panel, just make a call to setOnUpdateAction
panel.setOnUpdateAction(new Callback() {
public void action(int v) {
countLabel.setText(" Count #" + v);
}
});
Since there is only one method and one instruction, you can use a shorter Lambda syntax similar to the one you used in the Timer
panel.setOnUpdateAction(v -> countLabel.setText(" Count #" + v));
( I had to make the countLabel a field to access it inside GUI.)
And there you have it !
Here's the full modified code :
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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论