How do I make the lines draw without an actionlistener?

I am writing a GUI that is supposed to write lines and circles to a panel and I am supposed to use sliders to change how fast they add to the panel. I am supposed to add a clear button that will clear the entire panel and then when I move the sliders they should make the circles and lines begin to write on the panel again. There should be a specific stop point at the beginning of the sliders. We have been told to do this without actionlisteners on the sliders. I am having some trouble understanding how to make that work.

Below are the requirements for the assignment: Write a Swing program that provides the following functionality:

Draw random length lines of random color at random coordinates with pauses between the drawing of each line.

Allow the user to set the length of the pause between lines with a slider. Have the slowest value actually stop drawing lines (i.e., it slows to a stop once it is at that value on the slider).

Have a clear button that clears all the lines & circles. Be sure that the clear button is operational at all times.

Draw random size circles of random color at random coordinates with pauses between the drawing of each circle. (Use draw, not fill.)

Allow the user to set the length of the pause between circles with a slider. Have the slowest value actually stop drawing circles (i.e., it slows to a stop once it is at that value on the slider). This is independent of the lines' speed.

The circles and lines are both drawn independently, each in their own Thread. Do not use Timer for this, extend Thread and/or Runnable.

    public class OhMy extends JFrame 
    {
        private static final int MAX_COLOR = 225;
        private static final long STOP_SLEEP = 0;

        public OhMy()
        {
            this.setTitle("Oh My Window");
            Container canvas = this.getContentPane();
            canvas.setLayout(new GridLayout(2,1));              
            JPanel panControl = new JPanel(new GridLayout(1,1));
            JPanel panDraw = new JPanel(new GridLayout(1,1));
            canvas.add(panControl);
            canvas.add(panDraw);                
            panControl.add(createPanControl());
            panDraw.add(createPanDraw());
            this.setSize(800, 600);
            this.setVisible(true);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }

        private JPanel createPanControl()
        {
            JPanel panControl = new JPanel();
            JLabel lines = new JLabel("Lines");
            panControl.add(lines);
            lines.setForeground(Color.RED);
            JSlider sldSpeedLines = new JSlider(1, 30, 5);
            panControl.add(sldSpeedLines);
            JButton btnClear = new JButton("Clear");
            panControl.add(btnClear);
            btnClear.setForeground(Color.RED);
            JSlider sldSpeedCircles = new JSlider(0, 30, 5);
            panControl.add(sldSpeedCircles);
            JLabel circles = new JLabel("Circles");
            panControl.add(circles);
            circles.setForeground(Color.RED);               
            btnClear.addActionListener((e)->
            {
                repaint();                  
            });             
            return panControl;              
        }           
        private JPanel createPanDraw()
        {
            JPanel panDraw = new JPanel();              
            class LinesThread extends Thread 
            {
                @Override
                public void run()
                {
                    try
                    {
                      Graphics g = panDraw.getGraphics();
                       while(g == null)
                        {
                         Thread.sleep(STOP_SLEEP);
                          g = panDraw.getGraphics();
                         }
                      Random rand = new Random();
                      int red = rand.nextInt(MAX_COLOR);
                      int green = rand.nextInt(MAX_COLOR);
                      int blue = rand.nextInt(MAX_COLOR);    
                      Color color = new Color(red, green, blue);    
                      int x1 = rand.nextInt(panDraw.getWidth());
                      int y1 = rand.nextInt(panDraw.getHeight());
                      int x2 = rand.nextInt(panDraw.getWidth());
                      int y2 = rand.nextInt(panDraw.getHeight());               
                      g.setColor(color);
                      g.drawLine(x1, y1, x2, y2);
                    }
                    catch(InterruptedException e1)
                    {
                        //awake now
                    }
                }
            }
            return panDraw;             
        }

    /**
     * @param args
     */
    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new OhMy();
            }
        });    
    }    
}

Upvotes: 0

Views: 82

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

You state:

"We have been told to do this without actionlisteners on the sliders..."

  • Good, because JSliders won't accept an ActionListener.
  • JSliders will accept a ChangeListener though, but you likely don't even need to use this.
  • Instead, give the clear button an ActionListener (you've no way to get around using ActionListeners at all).
  • In that ActionListener, reset the drawing and get the values from the JSliders by simply calling getValue() on it.
  • Don't get your Graphics object by calling getGraphics() on the JPanel since the Graphics object thus obtained will not be stable risking a broken image, or worse, a NullPointerException (to see what I mean, minimize and restore your current application while its drawing).
  • Instead either draw on a BufferedImage that is displayed in the JPanel's paintComponent method or draw directly in paintComponent itself.
  • Avoid using a Thread and Thread.sleep, but instead use a Swing Timer -- it's much easier this way to be sure that your code is threading appropriately.
  • Use this value to adjust the speed of your Swing Timer.

Edit
Thanks to Abishek Manoharan for pointing out problems in my answer...

  • If the JSliders need to change the speed of drawing while the drawing is proceeding, then you will in fact need to use ChangeListener on the slider.
  • In that listener change a field that will tell the Thread how long to sleep.
  • I see that you're also required to use background threads. If so, then be sure to make all Swing calls on the Swing event thread. So if you're in the background thread and need to make a Swing call, then queue it on the Swing event thread by calling SwingUtilities.invokeLater(...) and pass in a Runnable that has your Swing call.

Upvotes: 2

Related Questions