如何在一段时间后重新绘制面板上的符号?

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

How do I redraw symbols on the panel after some time?

问题

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

public class TestClass {

    private static JFrame frame;
    private static JPanel panel;
    private static char currentCharacter = '\u30A0';

    public static void main(String[] args) {

        frame = new JFrame();

        panel = new JPanel() {

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);

                g.setColor(Color.GREEN);
                g.setFont(new Font("ms mincho", Font.ROMAN_BASELINE, 20));

                g.drawString(String.valueOf(currentCharacter), 0, 20);
            }
        };
        panel.setBackground(Color.BLACK);

        frame.add(panel);

        frame.setSize(600, 800);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);

        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(5000); // Sleep for 5 seconds
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                currentCharacter++;
                panel.repaint();
            }
        }).start();
    }
}
英文:

I started making a small app on swing and ran into problems. I do not know how to draw a character (string) in a "for" loop on the panel, AFTER a CERTAIN AMOUNT of TIME(5 seconds), and so that the characters do not overlap each other on the panel, but so that the program does not stop working, but stops!

import javax.swing.*;
import java.awt.*;
public class TestClass {
private static JFrame frame;
private static JPanel panel;
public static void main(String[] args) {
frame = new JFrame();
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.setFont(new Font("ms mincho", Font.ROMAN_BASELINE, 20));
for (char c = '\u30A0'; c <= '\u30FF'; c++)
//Here the program should stop for a while, and the next character should not overlap the previous one.
// I tried using Thread.sleep() and IT DOESN't WORK AS it SHOULD, because the program is interrupted and the panel disappears.
g.drawString(String.valueOf(c), 0, 20);
}
};
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setSize(600, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

If you solve these problems, there is another one. In the loop, I will have to re-create the JPanel object each time and draw on it. And that's not good.

Thanks)

答案1

得分: 1

(我不是 Swing 高手,所以下面的答案可能不是最优的,欢迎任何改进。)

据我所记,Swing 有专门的线程负责绘制组件和处理事件。因此,如果你在 paintComponent 方法中放置了过多的逻辑(循环等),它将使该线程在处理完逻辑之前变得无响应,从而使应用程序看起来停止工作。

要解决这种问题,可以让 paintComponent 方法打印单个字符(这是 Swing 应该能够快速处理的简单逻辑),同时创建一个单独的线程,定期更新保存该字符的变量(更新字符后建议帧或面板再次重绘)。

因此,你的代码可能如下所示:

class TestClass {

    private static JFrame frame;
    private static JPanel panel;

    private static volatile char charToPrint = '\u30A0';

    public static void main(String[] args) {
        frame = new JFrame();
        panel = new JPanel() {
            Font ms_mincho = new Font("ms mincho", Font.ROMAN_BASELINE, 20);

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.GREEN);
                g.setFont(ms_mincho);
                g.drawString(String.valueOf(charToPrint), 0, 20);
            }
        };
        panel.setBackground(Color.BLACK);
        frame.add(panel);
        frame.setSize(600, 800);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);

        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            if (charToPrint == '\u30FF') // 如果是范围内的最后一个字符
                charToPrint = '\u30A0';   // 从第一个字符重新开始
            else
                charToPrint++;            // 否则设置下一个字符

            frame.repaint();            // 建议帧重新绘制其组件
                                        // 可能可以更改为 panel.repaint()
        }, 0, 100, TimeUnit.MILLISECONDS);
    }
}

注意:上述内容是对你提供的代码片段的翻译。如果需要更多帮助或有任何问题,请随时提问。

英文:

(I am not Swing guru so below answer may not be optimal, any improvements are welcome)

From what I remember Swing has its own dedicated thread which is responsible for drawing components and handling events. So if you place too much logic (loops, etc) in paintComponent method it will make that thread unresponsive until it will finish handling that logic which will make it look like your application stopped working.

To solve that kind of problem make paintComponent print single character (that is simple logic which swing should be able to handle quickly) but at the same time create separate thread which will periodically update variable which holds that character (and after updating character will suggest frame or panel to repaint itself again).

So your code can look something like:

class TestClass {
private static JFrame frame;
private static JPanel panel;
private static volatile char charToPrint = '\u30A0';
public static void main(String[] args) {
frame = new JFrame();
panel = new JPanel() {
Font ms_mincho = new Font("ms mincho", Font.ROMAN_BASELINE, 20);
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.setFont(ms_mincho);
g.drawString(String.valueOf(charToPrint), 0, 20);
}
};
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setSize(600, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(() -> {
if (charToPrint == '\u30FF')//if last character in range
charToPrint = '\u30A0'; //start over from first
else
charToPrint++;          //else set next character
frame.repaint();            //suggest frame to repaint its component
//probably can be change to panel.repaint()
}, 0, 100, TimeUnit.MILLISECONDS);
}
}

答案2

得分: -1

这是我对解决方案的看法。您需要创建某种线程来倒计时。我使用了javax.swing中的一个线程:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.ArrayList;
import javax.swing.Timer;

public class TestClass {

    private static JFrame frame;
    private static JPanel panel;
    private static List<Character> chars = new ArrayList<>();
    private static int currentIndex = 0;

    public static void main(String[] args) {

        // 预先创建字符数组...
        for (char c = '\u30A0'; c <= '\u30FF'; c++) {
            chars.add(Character.valueOf(c));
        }

        // 当定时器触发时调用delayedPaint()。更新字符数组中的索引;
        // 在必要时重置。调用repaint()来重新绘制屏幕...
        ActionListener delayedPaint = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                currentIndex++;
                if (currentIndex == 95) {
                    currentIndex = 0;
                }
                panel.repaint();
            }
        };

        // 定时器设置...
        Timer timer = new Timer(500, delayedPaint);
        timer.setInitialDelay(1000);
        timer.setDelay(500);
        timer.start();

        frame = new JFrame();

        panel = new JPanel() {

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);

                g.setColor(Color.GREEN);
                g.setFont(new Font("ms mincho", Font.ROMAN_BASELINE, 20));

                // 您是否希望这些字符排成一行?我不太确定...
                int x = 10;
                int y = 20;
                for (int i = 0; i < currentIndex; i++) {
                    g.drawString(String.valueOf(chars.get(i)), x, y);
                    x += 20;
                    // 将y增加到下一行...
                    if (x > panel.getWidth()) {
                        x = 0;
                        y += 20;
                    }
                }
            }
        };
        panel.setBackground(Color.BLACK);

        frame.add(panel);

        frame.setSize(600, 800);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}
英文:

Here's my take on a solution. You have to create some sort of thread to
count down the time for you. I used the one in javax.swing:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.ArrayList;
import javax.swing.Timer;
public class TestClass {
private static JFrame frame;
private static JPanel panel;
private static List&lt;Character&gt; chars = new ArrayList&lt;&gt;();
private static int currentIndex = 0;
public static void main(String[] args) {
// create an array of characters up front...
for (char c = &#39;\u30A0&#39;; c &lt;= &#39;\u30FF&#39;; c++) {
chars.add(Character.valueOf(c));
}
// delayedPaint() called when timer fires. Updates the index
// into the character array; resets when necessary. Calls
// repaint() to redraw the screen...
ActionListener delayedPaint = new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentIndex++;
if (currentIndex == 95) {
currentIndex = 0;
}
panel.repaint();
}
};
// Timer setup...
Timer timer = new Timer(500, delayedPaint);
timer.setInitialDelay(1000);
timer.setDelay(500);
timer.start();
frame = new JFrame();
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.setFont(new Font(&quot;ms mincho&quot;, Font.ROMAN_BASELINE, 20));
// did you want these in a row? I wasn&#39;t sure...
int x = 10;
int y = 20;
for (int i = 0; i &lt; currentIndex; i++) {
g.drawString(String.valueOf(chars.get(i)), x, y);
x += 20;
// bumps y to the next row...
if (x &gt; panel.getWidth()) {
x = 0;
y += 20;
}
}
}
};
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setSize(600, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

huangapple
  • 本文由 发表于 2020年9月18日 01:11:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63943024.html
匿名

发表评论

匿名网友

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

确定