【问题标题】:draw a circle when certain condition is met满足一定条件时画圈
【发布时间】:2014-09-15 12:52:29
【问题描述】:

我的程序是将字母转换为一些信号。我的主要方法生成一些随机字母。字母被传递给另一个方法,该方法根据生成的字母调用 repaint() 方法。 PaintComponent() 方法用于绘制一个填充白色的圆圈。当我执行程序时,我只得到一个 Jframe。我没有看到圆圈。请帮忙。

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

  }
}

【问题讨论】:

  • 使用逻辑一致的代码格式风格!代码缩进旨在帮助人们遵循程序流程。

标签: java swing graphics awt frame


【解决方案1】:

两件事...

首先,在事件调度线程中调用Thread.sleep(2000); 将阻止 EDT 处理事件队列上的事件,包括绘制事件。

其次,Frame 没有paintComponent

添加@Override 注释并尝试调用super.paintComponent 会突出显示此问题,因为代码不会编译。

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

首先,首先使用JPanel 来保存您的核心逻辑并执行您的自定义绘画。

其次,使用javax.swing.Timer 来执行动画。详情请见How to use Swing Timers

更新

基本概念比较简单。您需要某种第二个/后台线程,它可以在输出更改之间产生延迟。然后,您需要根据您尝试显示的信息类型在每次延迟之前更新 UI。

实现变得棘手,因为与大多数 GUI 框架一样,Swing 是单线程的并且不是线程安全的。

这意味着,您不能阻塞 GUI 线程,这样做会阻止 UI 被重新绘制等,并且您必须从 GUI 线程的上下文中更新任何 UI 组件的状态。

这意味着虽然您可以使用 Thread 在后台运行,但您必须确保对 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 线程),它将无法绘制或响应用户输入。见Concurrency in Swing
  • 我在paint方法中添加了睡眠线程。我仍然没有得到预期的结果。就像案例 A 一样,它应该闪烁三次。对于案例 B,它应该闪烁两次,依此类推。有什么办法可以实现吗。请帮忙。
  • Swing 是一个单线程环境。任何阻塞 Swing 线程(如Thread.sleep)的东西都会阻止绘画的发生。
  • 我从 switch case 中删除了 Thread.sleep() 并将其添加到 Paint 方法中。我看到一个眨眼。但是从案例中调用 repaint() 并没有像我预期的那样工作(即在 JFrame 中重新绘制)。
  • 你没有抓住重点。在事件调度线程上下文中调用 Thread.sleep 将阻止 UI 被绘制,句号!唯一的解决方案是设置第二个线程,负责管理时间和更改 UI 的状态。这是有问题的,因为您不应该从除 EDT 之外的任何线程更改 UI 的状态,请参阅更新
猜你喜欢
  • 2013-06-24
  • 1970-01-01
  • 2023-02-22
  • 2020-06-19
  • 2017-02-20
  • 2018-04-03
  • 1970-01-01
  • 2014-12-01
  • 1970-01-01
相关资源
最近更新 更多