Java 在满足一定条件时画一个圆
我的程序是把字母转换成一些信号。我的主要方法是生成一些随机字母。该字母被传递给另一个方法,该方法根据生成的字母调用repaint方法。PaintComponent方法用于绘制一个填充白色的圆。当我执行该程序时,我只得到一个Jframe。我看不到圆圈,请帮忙Java 在满足一定条件时画一个圆,java,swing,graphics,awt,frame,Java,Swing,Graphics,Awt,Frame,我的程序是把字母转换成一些信号。我的主要方法是生成一些随机字母。该字母被传递给另一个方法,该方法根据生成的字母调用repaint方法。PaintComponent方法用于绘制一个填充白色的圆。当我执行该程序时,我只得到一个Jframe。我看不到圆圈,请帮忙 package morsecode; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Random; impo
package morsecode;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
import java.awt.*;
public class MorseCode extends Frame {
public static void main(String[] args) {
MorseCode mc = new MorseCode();
MorseCode frame = new MorseCode();
final String chars = "abcdefghijklmnopqrstuvwxyz1234567890";
char word;
for(int i=1;i<=1;i++)
{
Random rand = new Random();
int x = rand.nextInt(36);
word = chars.charAt(x);
System.out.print(word);
frame.setBackground(Color.BLACK);
frame.addWindowListener(
new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
}
);
frame.setSize(400, 400);
frame.setVisible(true);
mc.toMorseCode(word);
}
}
void toMorseCode(char letter)
{
switch(letter)
{
case 'A' | 'a':
repaint();
Thread.sleep(1000);
repaint();
Thread.sleep(2000);
break;
case 'B' | 'b':
repaint();
Thread.sleep(1000);
repaint();
Thread.sleep(1000);
repaint();
Thread.sleep(1000);
repaint();
Thread.sleep(2000);
break; ..............
}
}
public void paintComponent(Graphics g) {
Graphics2D ga = (Graphics2D)g;
ga.setColor(Color.white);
ga.fillOval(125,125,150,150);
}
}
有两件事
首先,调用Thread.sleep2000;事件调度线程将阻止EDT处理事件队列上的事件,包括绘制事件
第二,框架没有paintComponent
添加@Override注释并尝试调用super.paintComponent会突出显示此问题,因为代码不会编译
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
首先,使用JPanel保存核心逻辑并执行自定义绘制
其次,使用javax.swing.Timer执行动画。有关更多详细信息,请参阅
更新
基本概念相对简单。您需要某种第二/后台线程,它可以在输出中的更改之间生成延迟。然后,您需要在每次延迟之前根据您试图显示的信息类型更新UI
由于Swing和大多数GUI框架一样是单线程的,并且不是线程安全的,所以实现变得很棘手
这意味着,您不能阻止GUI线程,这样做将阻止重新绘制UI,并且您必须在GUI线程的上下文中更新任何UI组件的状态
这意味着,虽然可以使用线程在后台运行,但必须确保对UI的所有更改/修改仅在EDT内执行
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MorseCodeTest {
public static void main(String[] args) {
new MorseCodeTest();
}
public MorseCodeTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static final int GAP = 500;
public static final int DOT = 1000;
public static final int DASH = 4000;
public interface Transmitter {
public void setTap(boolean tap);
}
public class TestPane extends JPanel implements Transmitter {
private MorseCode code;
private boolean tapped;
public TestPane() {
code = MorseCode.create('A').addDot().addDash();
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
Signalar signalar = new Signalar(TestPane.this, code);
signalar.execute();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (tapped) {
Graphics2D g2d = (Graphics2D) g.create();
int diameter = Math.min(getWidth(), getHeight()) / 2;
int x = (getWidth() - diameter) / 2;
int y = (getHeight() - diameter) / 2;
g2d.fillOval(x, y, diameter, diameter);
g2d.dispose();
}
}
@Override
public void setTap(boolean tap) {
tapped = tap;
repaint();
}
}
public class Signalar extends SwingWorker<Void, Boolean> {
private final MorseCode code;
private final Transmitter transmitter;
public Signalar(Transmitter transmitter, MorseCode code) {
this.code = code;
this.transmitter = transmitter;
}
@Override
protected void process(List<Boolean> chunks) {
transmitter.setTap(chunks.get(chunks.size() - 1));
}
@Override
protected Void doInBackground() throws Exception {
for (Tone tone : code.getTones()) {
publish(true);
Thread.sleep(tone.getDelay());
publish(false);
Thread.sleep(GAP);
}
return null;
}
}
public static class Tone {
private final int delay;
public Tone(int delay) {
this.delay = delay;
}
public int getDelay() {
return delay;
}
}
public static class DashTone extends Tone {
public DashTone() {
super(DASH);
}
}
public static class DotTone extends Tone {
public DotTone() {
super(DOT);
}
}
public static class MorseCode {
private final char value;
private final List<Tone> tones;
public static MorseCode create(char value) {
MorseCode code = new MorseCode(value);
return code;
}
public MorseCode(char value) {
this.value = value;
this.tones = new ArrayList<>(25);
}
public char getValue() {
return value;
}
public MorseCode addDash() {
return addTone(new DashTone());
}
public MorseCode addDot() {
return addTone(new DotTone());
}
public MorseCode addTone(Tone tone) {
tones.add(tone);
return this;
}
public Iterable<Tone> getTones() {
return tones;
}
}
}
使用逻辑一致的代码格式样式!代码缩进旨在帮助人们遵循程序流程。Swing是一个单线程框架,这意味着如果您阻止事件调度线程主UI线程,它将无法绘制或响应用户输入。看我在画法里面加了睡眠线。我仍然没有得到预期的结果。就像案例A一样,它应该闪烁三次。对于情况B,它应该闪烁两次,以此类推。有没有办法实现它。请帮助。Swing是一个单线程环境。任何阻止Swing thread(如thread.sleep)的操作都会阻止绘制。我从开关盒中删除了thread.sleep,并将其添加到绘制方法中。我看到一个眨眼。但是从case调用repaint并不能像我预期的那样在JFrame中重新绘制。你没有抓住要点。在事件调度线程上下文中调用Thread.sleep将阻止用户界面被绘制,到此为止!唯一的解决方案是设置第二个线程,负责管理计时和更改UI的状态。这是有问题的,因为您不应该从EDT以外的任何线程更改UI的状态,请参阅更新