Updating JLabel everytime Frame’s panel is updated

huangapple go评论78阅读模式
英文:

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

Updating JLabel everytime Frame’s panel is updated

英文:

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(&quot;   Count #&quot; + 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 -&gt; countLabel.setText(&quot;   Count #&quot; + v));

( I had to make the countLabel a field to access it inside GUI.)

And there you have it !

Updating JLabel everytime Frame’s panel is updated

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 -&gt; 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 &lt; (number * 20); i++) {
            for (int j = 0; j &lt; (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(&quot;   Count #&quot; + v);
            }
        });

        // You can also use this lambda syntax ( since Callback has only 1 method to implement )
        // panel.setOnUpdateAction(v -&gt; countLabel.setText(&quot;   Count #&quot; + 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(&quot;CountLabel&quot;);
        countLabel.setText(&quot;   Count #&quot; + number);
        countLabel.setFont(new Font(&quot;Comic Sans MS&quot;, 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);
    }
}

huangapple
  • 本文由 发表于 2020年8月28日 16:19:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/63630043.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定