簡體   English   中英

使用線程重繪()組件

[英]Using a thread to repaint() components

看來我的線程從未啟動過。 那個或者run方法實際上什么也沒做,因此我無法解釋。

我在按鈕StartRace上有一個偵聽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();
       }    
   }
}

主要是

您永遠不會將ActionListener添加到兩個按鈕中,因此在激活它們時沒有任何響應

另外

  1. 狀態管理無處不在。 blueDrawredDraw應該是ConcurrencyPanel實例字段。
  2. 不要從任何繪制方法中更新UI的狀態(或UI依賴的變量)。 繪制方法應繪制狀態,而不是更改狀態。 應該使用特定的方法來更新blueDrawredDraw ,當需要更新時可以調用該方法。

所有這些使我相信您最好使用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的簡單觀察者模式來RacePane

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM