0

I'm trying to "light up" a list of JLabels as if it were a string of lights. Anyway, I have a simple gui that has a JPanel which is an array of JLabel's. I have been using a timer and changing the background color from black to green to look like they "light up." I have figured out the code to light them going up, but going back down seems to be a problem.

Working Code so far:

    this.timer = new Timer(100, new ActionListener() {
        private int sequence = 0;

        public void actionPerformed(ActionEvent evt) {

            if (sequence % 2 == 0) {
                labels[1].setBackground(Color.black);
                labels[3].setBackground(Color.black);
                labels[5].setBackground(Color.black);
                labels[7].setBackground(Color.black);
                labels[sequence].setBackground(Color.green);
                sequence++;
            } else if (sequence % 2 != 0) {
                labels[0].setBackground(Color.black);
                labels[2].setBackground(Color.black);
                labels[4].setBackground(Color.black);
                labels[6].setBackground(Color.black);
                labels[sequence].setBackground(Color.green);
                sequence++;
            }

            if (sequence > 7) {
                sequence = 0;
            }


        }

    });
    this.timer.start();

}
Ashton
  • 119
  • 3
  • 4
  • 14
  • For the people who don't know `Battlestar Galactica and the old Knight Rider`, myself included, What is a `Larson Scanner`? – Paul Samsotha Nov 03 '13 at 21:00
  • And consider posting a compilable runnable [sscce](http://sscce.org). – Hovercraft Full Of Eels Nov 03 '13 at 21:03
  • It what a light that would go from left to right then back left to the beginning then repeat. It was on the car in Knight Rider and the cylons in Battlestar Galactica. http://www.youtube.com/watch?v=YPL7QPCfVZc is a link to a video showing you what the light should look like. I'm just trying to simulate it and get more practice with GUIs – Ashton Nov 03 '13 at 21:04
  • Assuming you have 10 lights in a row, turn them all off, then turn the first light on. Turn them all off, then turn the second light on. And so on. The trick is to go from light 0 through 9, then light 8 through 1. You can put the light sequence numbers in a List, then go through the List over and over. – Gilbert Le Blanc Nov 03 '13 at 21:26

2 Answers2

2

I would use a count variable to iterate through my array or collection, and would set the label to the right of the index label to the background color, set the index label to the active color, and advance the index. For example:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;    
import javax.swing.*;

@SuppressWarnings("serial")
public class LarsonScanner extends JPanel {
   private static final int PANEL_COUNT = 50;
   private static final int TIMER_DELAY = 30;
   private static final Color BACKGROUND = Color.BLACK;
   private static final Color ACTIVE_COLOR = Color.GREEN;
   private static final Color PARTIAL_COLOR = new Color(0, 90, 0);
   private static final Dimension RIGID_AREA = new Dimension(14, 1);

   private JPanel[] panels = new JPanel[PANEL_COUNT];

   public LarsonScanner() {
      setLayout(new GridLayout(1, 0));
      for (int i = 0; i < panels.length; i++) {
         panels[i] = new JPanel();
         panels[i].add(Box.createRigidArea(RIGID_AREA));
         panels[i].setBackground(BACKGROUND);
         add(panels[i]);
      }
      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   private class TimerListener implements ActionListener {
      private int count = 0;

      @Override
      public void actionPerformed(ActionEvent e) {
         int index = (count - 2 + panels.length) % panels.length;
         panels[index].setBackground(BACKGROUND);
         int prior = (count - 1 + panels.length) % panels.length;
         int next = (count + 1) % panels.length;
         panels[count].setBackground(ACTIVE_COLOR);
         panels[prior].setBackground(PARTIAL_COLOR);
         panels[next].setBackground(PARTIAL_COLOR);
         count++;
         count %= panels.length;
      }
   }

   private static void createAndShowGui() {
      LarsonScanner mainPanel = new LarsonScanner();

      JFrame frame = new JFrame("LarsonScanner");
      frame.setDefaultCloseOperation(JFrame.EXIT_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();
         }
      });
   }
}

Edit 2
Iteration 2 of the program:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

@SuppressWarnings("serial")
public class LarsonScanner extends JPanel {
   private static final int PANEL_COUNT = 40;
   private static final int TIMER_DELAY = 20;
   private static final Color BACKGROUND = Color.BLACK;
   private static final Color ACTIVE_COLOR = Color.GREEN;
   private static final Color PARTIAL_COLOR = new Color(0, 90, 0);
   private static final Dimension RIGID_AREA = new Dimension(14, 1);

   private JPanel[] panels = new JPanel[PANEL_COUNT];

   public LarsonScanner() {
      setLayout(new GridLayout(1, 0));
      for (int i = 0; i < panels.length; i++) {
         panels[i] = new JPanel();
         panels[i].add(Box.createRigidArea(RIGID_AREA));
         panels[i].setBackground(BACKGROUND);
         add(panels[i]);
      }
      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   private class TimerListener implements ActionListener {
      private int count = 0;
      private boolean goingRight = true;

      @Override
      public void actionPerformed(ActionEvent e) {
         if (goingRight) {
            int index = (count - 2 + panels.length) % panels.length;
            panels[index].setBackground(BACKGROUND);
            int prior = Math.max((count - 1) % panels.length, 0);
            int next = Math.min(count + 1, panels.length - 1);
            panels[prior].setBackground(PARTIAL_COLOR);
            panels[next].setBackground(PARTIAL_COLOR);
            panels[count].setBackground(ACTIVE_COLOR);
            count++;
            if (count == panels.length) {
               count--;
               goingRight = false;
            }
         } else {
            int index = (count + 2) % panels.length;
            panels[index].setBackground(BACKGROUND);
            int prior = Math.max((count - 1) % panels.length, 0);
            int next = Math.min(count + 1, panels.length - 1);
            panels[prior].setBackground(PARTIAL_COLOR);
            panels[next].setBackground(PARTIAL_COLOR);
            panels[count].setBackground(ACTIVE_COLOR);
            count--;
            if (count == -1) {
               count++;
               goingRight = true;
            }
         }
      }
   }

   private static void createAndShowGui() {
      LarsonScanner mainPanel = new LarsonScanner();

      JFrame frame = new JFrame("LarsonScanner");
      frame.setDefaultCloseOperation(JFrame.EXIT_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();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • This related [example](http://stackoverflow.com/a/2124507/230513) varies the color's saturation. – trashgod Nov 03 '13 at 22:29
  • Can you explain to me how you can make them go backwards? I mean lighting down after reaching 8 going back down to 7 and so on and so forth until reaching zero and beginning over again. By the way, I really like the "fade" effect you thought to put in there. – Ashton Nov 04 '13 at 01:39
1

I expanded on my comment. I used a List to make the back and forth scanning easier.

Here's a picture of the LarsonScanner test.

enter image description here

Here's the LarsonScanner JPanel class.

package com.ggl.larson.scanner;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class LarsonScanner extends JPanel {
    private static final long   serialVersionUID    = 8213921815383053375L;

    private static int          index               = 0;

    private int                 width;
    private int                 height;
    private int                 widthInterval;
    private int                 gap;

    private int                 segmentCount;

    private long                displayInterval;

    private List<Integer>       sequence;

    public LarsonScanner() {
        this.height = 16;
        this.width = 0;

        this.segmentCount = 10;
        this.displayInterval = 200L;

        this.sequence = new ArrayList<Integer>();
        setSequence();
    }

    public void setSegmentCount(int segmentCount) {
        this.segmentCount = segmentCount;
        setSequence();
    }

    public void setDisplayInterval(long displayInterval) {
        this.displayInterval = displayInterval;
    }

    private void setSequence() {
        this.sequence.clear();

        for (int i = 0; i < segmentCount; i++) {
            this.sequence.add(Integer.valueOf(i));
        }

        for (int i = segmentCount - 2; i > 0; i--) {
            this.sequence.add(Integer.valueOf(i));
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        if (width <= 0) {
            width = (getSize().width - segmentCount * 3) / segmentCount;
            widthInterval = getSize().width / segmentCount;
            gap = (getSize().width - widthInterval * segmentCount + 3) / 2;
            new Thread(new SequenceRunnable()).start();
        }

        g.setColor(Color.BLUE);
        for (int i = 0; i < segmentCount; i++) {
            int x = i * widthInterval + gap;
            g.fillRect(x, 0, width, height);
        }

        g.setColor(Color.RED);
        int x = sequence.get(index) * widthInterval + gap;
        g.fillRect(x, 0, width, height);
        index = ++index % sequence.size();
    }

    public class SequenceRunnable implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(displayInterval);
                } catch (InterruptedException e) {
                }

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        repaint();
                    }
                });
            }
        }

    }
}

Here's a TesterFrame class that shows how to use the LarsonScanner class.

package com.ggl.larson.scanner;

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TesterFrame implements Runnable {

    @Override
    public void run() {
        JFrame frame = new JFrame("Larson Scanner");

        LarsonScanner scanner = new LarsonScanner();
        scanner.setSegmentCount(12);
        scanner.setDisplayInterval(100L);
        frame.add(scanner);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(600, 100));
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TesterFrame());
    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111