【问题标题】:Two ScheduledExecutorService overriding eachother?两个 ScheduledExecutorService 互相覆盖?
【发布时间】:2014-10-26 00:25:39
【问题描述】:

我正在尝试制作两个以不同速率闪烁的闪烁圆圈。我在 Circle 类中使用 ScheduledExecutorService 来调节闪烁,其持续时间由每个 Circle 中的 ms(毫秒)变量设置。

当我单独制造一辆车时,它们会以正确的速率闪烁(我将黑色设置为 1000 毫秒,红色设置为 10 毫秒)。但是,当我创建它们并将它们添加到我的 JLayeredPane 时,它​​们都会在较短的时间内闪烁。

我对 ScheduledExecutorService 的使用不太熟悉,所以如果有人能帮助我解决问题所在,将不胜感激!

import java.awt.Color;
import java.awt.Graphics;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

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

public class blinker extends JFrame
{
    JLayeredPane lp = new JLayeredPane();
    public carlight()
    {
        lp.setLayout(new BorderLayout());
        lp.setPreferredSize(new Dimension(450, 450));

        car c1 = new car(new Color(0, 0, 0), "1", 10, 0, 0);
        c1.setOpaque(false);
        car c2 = new car(new Color(255, 0, 0), "2", 1000, 100, 100);
        c2.setOpaque(false);
        c1.setBounds(0, 0, 450, 450);
        c2.setBounds(0, 0, 450, 450);

        lp.add(c2);
        lp.add(c1);

        add(lp);

        setTitle("Carlights");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);
        setVisible(true);
    }

    public static void main(String[] args)
    {
        carlight cl = new carlight();
    }
}

class Circle extends JPanel
{
    private Color color;
    private String name;
    private long ms;
    private int x, y;
    private boolean on = true;
    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponents(g);
        if(on)
        {
            g.setColor(color);
            int r = 50;
            g.fillOval(x, y, r, r);
            on = false;
        }
        else
        {
            on = true;
        }
    }

    public car(Color c, String s, long l, int x, int y)
    {
        color = c;
        name = s;
        ms = l;
        this.x = x;
        this.y = y;

        this.service.scheduleAtFixedRate(new Runnable()
        {
            public void run()
            {
                repaint();
            }
        }, 0, ms, TimeUnit.MILLISECONDS);
    }
}

【问题讨论】:

    标签: java swing graphics executor scheduledexecutorservice


    【解决方案1】:

    您的问题是您在paintComponent 方法中有程序逻辑,您可以在其中更改布尔变量的状态。您无法完全控制何时或什至何时调用此方法,实际上 both paintComponents 将在调用 repaint 时被调用,这就是您的闪光灯不工作的原因。解决方案:通过在其他地方更改布尔字段的状态,从 paintComponent 方法中获取逻辑。此外,您还需要使用 Swing Timer 来获得更好的 Swing 线程。

    您还需要修正对布局的使用,包括避免使用 setBounds。这在您的设置中尤其危险且不可预测,将其与 BorderLayout 一起使用。我自己,我不会让 Circle 类扩展 JPanel,而是让它成为一个逻辑类,而不是组件类,然后我将拥有绘图组件,一个扩展 JPanel 的类,保存 Circle 类的实例,然后在它的paintComponent 中绘制它们。例如:

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class BlinkerEg extends JPanel {
       private static final int PREF_W = 450;
       private static final int PREF_H = PREF_W;
       private List<Circle> circles = new ArrayList<>();
    
       public BlinkerEg() {
          circles.add(new Circle(Color.red, 1000, 0, 0, 450, this));
          circles.add(new Circle(Color.black, 60, 0, 0, 450, this));
       }
    
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PREF_W, PREF_H);
       }
    
       @Override
       protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2 = (Graphics2D) g;
          g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
          for (Circle circle : circles) {
             circle.paint(g2);
          }
       }
    
       private static void createAndShowGui() {
          BlinkerEg mainPanel = new BlinkerEg();
    
          JFrame frame = new JFrame("BlinkerEg");
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.getContentPane().add(mainPanel);
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    
    class Circle {
       private Color color;
       private int x, y;
       private int diam;
       private JComponent component;
       private boolean on = true;
    
       public Circle(Color color, int ms, int x, int y, int diam, JComponent component) {
          this.color = color;
          this.x = x;
          this.y = y;
          this.diam = diam;
          this.component = component;
    
          new Timer(ms, new TimerListener()).start();
       }
    
       public void paint(Graphics g) {
          if (on) {
             g.setColor(color);
             g.fillOval(x, y, diam, diam);
          }
       }
    
       public boolean isOn() {
          return on;
       }
    
       public void setOn(boolean on) {
          this.on = on;
       }
    
       private class TimerListener implements ActionListener {
          @Override
          public void actionPerformed(ActionEvent e) {
             setOn(!isOn());
             component.repaint();
          }
       }
    }
    

    【讨论】:

    • 这正是我想要的,谢谢! (:您是否也知道如何让它们在闪烁后移动位置?我尝试在绘画方法中在绘画之前更改 x 和 y,但它的移动速度似乎与闪烁完全不同。无论如何感谢一堆为您的帮助!
    • @user3622688:同样,不要更改paint或paintComponent中的对象状态。这些方法仅用于绘画和绘画。您将更改 Timer 的 ActionListener 中的位置,就像更改闪烁布尔值的状态一样。
    猜你喜欢
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 2021-06-12
    • 1970-01-01
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多