使用线程重绘()组件

时间:2017-11-20 00:16:25

标签: java multithreading swing awt

似乎我的线程没有启动。要么run方法实际上没有做任何事情,我无法解释。

我的按钮StartRace上有一个监听器,它应该启动线程,这将增加每个矩形的长度,直到其中一个长度足以被宣布为胜利者(超过窗口的宽度,250px )。

我将最初绘制的所有组件都绘制到屏幕上,但它们从未重新绘制过。我称之为方法的方式有问题吗?我是否有其他不应该嵌套的类?

//--------------------------------------------------------------
//    Start a race between blue and red, track the winner
//    Use threads to manage each rectangle's movement
//    Allow for user interaction, like stopping and starting
//--------------------------------------------------------------


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

public class ConcurrencyRace extends JFrame
{ 
   private ConcurrencyPanel panel = new ConcurrencyPanel(); 
   private JButton startRace = new JButton("Start The Race!");
   private JButton stopRace = new JButton("Stop The Race!");
   private JLabel winnerText = new JLabel("Winner: ");
   private int blueDraw = 5, redDraw = 5;
   private Random rn = new Random();

   //-----------------------------------------------------------------
   //  Creates and displays the main program frame.
   //-----------------------------------------------------------------

   public ConcurrencyRace() {
       super("Concurrency");
       setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
       Container cp = getContentPane();
       cp.add(panel, BorderLayout.CENTER);
       JPanel p = new JPanel();
       p.add(startRace);
       p.add(stopRace);
       cp.add(p, BorderLayout.NORTH);
       cp.add(winnerText, BorderLayout.SOUTH);
       pack();
       setVisible(true);
   }

   public static void main (String[] args)
   {
       ConcurrencyRace tRun = new ConcurrencyRace();
       tRun.setVisible(true);
   }

   private class ConcurrencyPanel extends JPanel 
   {
       public class runnerThread extends Thread {
           @Override
           public void run() {
               while (blueDraw < 250 && redDraw < 250) {

                   panel.validate();
                   panel.repaint();

                   try {
                       Thread.sleep(200);
                   } catch (InterruptedException e) {}
               }
           }
       }

       public ConcurrencyPanel ()
       {
           setPreferredSize(new Dimension(600,250));

       }

       private class ButtonListener implements ActionListener {

           runnerThread rectDraw = new runnerThread();

           //--------------------------------------------------------------
           //  Starts the thread to draw each rectangle ("racer")
           //--------------------------------------------------------------
           public void actionPerformed (ActionEvent event)
           {
               if (event.getSource() == startRace) {                   
                   rectDraw.start();
               }
           }
       }
       @Override
       public void paintComponent (Graphics page) {

           super.paintComponent(page);
           page.setColor(Color.blue);
           page.fillRect(0,80,blueDraw,20);

           page.setColor(Color.red);
           page.fillRect(0,120,redDraw,20);

           blueDraw += rn.nextInt(10) + 1;
           redDraw += rn.nextInt(10) + 1;

           page.dispose();
       }    
   }
}

1 个答案:

答案 0 :(得分:2)

主要

你永远不会在你的任何一个按钮上添加ActionListener,所以当它们被激活时没有任何响应

另外

  1. 国家管理层到处都是。 blueDrawredDraw应为ConcurrencyPanel
  2. 的实例字段
  3. 不要在任何paint方法中更新UI的状态(或UI所依赖的变量)。绘制方法应该绘制状态,而不是更改它。更新blueDrawredDraw应以特定方法完成,可在需要更新时调用。
  4. 所有这些让我相信你更善于使用Swing Timer

    概念上...

    你可以这样做......

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    public class ConcurrencyRace {
    
        //-----------------------------------------------------------------
        //  Creates and displays the main program frame.
        //-----------------------------------------------------------------
        public ConcurrencyRace() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    Timer timer = new Timer(200, null);
                    JFrame frame = new JFrame();
                    frame.add(new ButtonPane(timer), BorderLayout.NORTH);
                    frame.add(new RacePane(timer));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public static void main(String[] args) {
            new ConcurrencyRace();
        }
    
        public class ButtonPane extends JPanel {
    
            private JButton startRace = new JButton("Start The Race!");
            private JButton stopRace = new JButton("Stop The Race!");
    
            public ButtonPane(Timer timer) {
                startRace.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        timer.start();
                    }
                });
    
                stopRace.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        timer.stop();
                    }
                });
    
                setLayout(new GridBagLayout());
                add(startRace);
                add(stopRace);
            }
    
        }
    
        private class RacePane extends JPanel {
    
            private int blueDraw = 5, redDraw = 5;
            private Random rn = new Random();
    
            public RacePane(Timer timer) {
                timer.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (updateState()) {
                            ((Timer)e.getSource()).stop();
                        }
                    }
                });
            }
    
            protected boolean updateState() {
                blueDraw += rn.nextInt(10) + 1;
                redDraw += rn.nextInt(10) + 1;
                repaint();
    
                return blueDraw >= getWidth() || redDraw >= getWidth();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600, 250);
            }
    
            @Override
            public void paintComponent(Graphics page) {
                System.out.println(">>");
                super.paintComponent(page);
                page.setColor(Color.blue);
                page.fillRect(0, 80, blueDraw, 20);
    
                page.setColor(Color.red);
                page.fillRect(0, 120, redDraw, 20);
            }
        }
    }
    

    这将Timer作为中心概念,在按钮和竞赛面板之间共享。

    我没有添加对生成获胜者通知的支持,这可以通过传递给RacePane

    的简单观察者模式来完成