2017-01-07 71 views
0

我創建了一個應用程序,它包含一個正方形,每次觸及frame的邊緣時都會彈出一個正方形。我沒有問題發起應用程序,問題是我不知道如何創建各種線程以便擁有框架內的多個正方形。 我嘗試了多件事,但我無法弄清楚我應該在哪裏創建線程。 我還注意到,只有當我直接將其添加到框架內而不是當我將它放入JPanel內時,該正方形纔可見。如何用paintComponent()多線程?

Square.java

public class Square extends JComponent implements ActionListener { 

    int width = 20; 
    int height = 20; 
    double y = Math.random() * 360; 
    double x = Math.random() * 360; 
    boolean xMax = false; 
    boolean yMax = false; 
    boolean xMin = true; 
    boolean yMin = true; 
    Rectangle2D.Double square = new Rectangle2D.Double(x, y, width, height); 

    public Square() { 
    Timer t = new Timer(2, this); 
    t.start(); 
    } 

    public void paintComponent(Graphics g) { 
    Graphics2D g2 = (Graphics2D) g; 
    super.paintComponent(g); 
    g2.setColor(Color.BLUE); 
    g2.fill(square); 

    x_y_rules(); 


    } 
    public void x_y_rules() { 
    if (xMax == true) { 
     x = x - 0.5; 
     if (x <= 0) { 
      xMax = false; 
     } 
    } else { 
     x = x + 0.5; 
     if (x >= this.getWidth()) { 
      xMax = true; 
     } 
    } 
    if (yMax == true) { 
     y = y - 0.5; 
     if (y <= 0) { 
      yMax = false; 
     } 
    } else { 
     y = y + 0.5; 
     if (y >= this.getHeight()) { 
      yMax = true; 
     } 
    } 
    square.setFrame(x, y, width, height); 
    } 

@Override 
public void actionPerformed(ActionEvent arg0) { 
    repaint(); 
} 
} 

App.java

public class App extends JFrame { 

public static void main(String[] args) { 
    JFrame jf = new JFrame(); 
    Square sqr = new Square(); 
    jf.setSize(400, 400); 
    jf.setVisible(true); 
    jf.add(sqr); 
    jf.setDefaultCloseOperation(EXIT_ON_CLOSE); 
    jf.setLocationRelativeTo(null); 
} 
} 

這是正常的,儘管我把2時定時器內,廣場上移動很慢?

+0

謝謝。我把x_y_rules()方法ActionListener.The問題內部是,如果一個創建另一個正方形,我將它添加到幀,後者只顯示一個正方形。這就是爲什麼我認爲我應該使用線程。 – TomCa

+0

由於您不使用線程來解決佈局管理器問題,因此您將需要研究佈局管理器。 JFrame contentPane使用BorderLayout,並且當您將組件默認添加到JFrame時,只會顯示最近添加的組件。 –

回答

2

問題:

  1. 你有程序邏輯,該x_y_rules()方法調用,該方法的paintComponent裏面。因爲它不屬於那裏,所以把它放到它所屬的Timer的ActionListener代碼中。
  2. 如果你願意,你可以給每個Square自己的Swing Timer。這不是一個真正的線程問題,因爲每個Timer的ActionListener都會在EDT上運行。
  3. 兩毫秒是期望在擺動計時器中使用的不切實際的時間片,並且沒有計時器會快速運行。 11到13是最快的期望或希望。
  4. 如果您希望精靈的移動速度更快,請爲您的移動代碼中的delta-x和delta-y賦予更大的值。
  5. 您的JComponent沒有定義首選大小,這可能是爲什麼它不會顯示在JPanel中,因爲默認的FlowLayout會將其大小設置爲[0,0]。覆蓋其getPreferredSize()並使其返回合理的尺寸值。
  6. 在添加所有組件之前,您正在對JFrame調用setVisible(true),這是一個禁忌。

好吧,我把getPrefferedSize()方類中,但我遇到了一個問題:正方形不是「在一起」,這就像他們在不同的面板

反彈

然後你的程序結構壞了。你真的不想創建單獨的Swing組件,事實上你的Square類不應該擴展JComponent或JPanel。相反

  • 廣場應該是一個合乎邏輯的,一個從一無所有(除默認對象等)延伸。
  • 給它的繪圖方法,說public void draw(Graphics g) {....}
  • 創建一個類繼承JPanel,說叫DrawingPanel,並覆蓋其的paintComponent方法。
  • 爲DrawingPanel類指定一個ArrayList<Square>,以便它可以容納多個Square對象。
  • 給這個DrawingPanel類Swing的計時器
  • 在DrawingPanel類的計時器,有它更新ArrayList中的所有方的位置,然後調用repaint()
  • 在paintComponent方法裏面,通過在所有的廣場迭代該列表使用for循環,並調用每個人的繪製方法。

例如:

enter image description here

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.image.BufferedImage; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class DrawingPanel extends JPanel { 
    private static final int PREF_W = 600; 
    private static final int PREF_H = PREF_W; 
    private static final int TIMER_DELAY = 20; 
    private static final Color[] SQUARE_COLOR = { Color.BLUE, Color.CYAN, Color.DARK_GRAY, 
      Color.BLACK, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, 
      Color.PINK, Color.RED, Color.YELLOW }; 
    List<Square> squareList = new ArrayList<>(); 

    public DrawingPanel() { 
     // create a bunch of squares 
     for (int i = 0; i < SQUARE_COLOR.length; i++) { 
      squareList.add(new Square(SQUARE_COLOR[i], PREF_W, PREF_H)); 
     } 

     setBackground(Color.WHITE); 

     // create and start the timer 
     new Timer(TIMER_DELAY, new TimerListener()).start(); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     // simply draw all the squares in the list 
     for (Square square : squareList) { 
      square.draw(g); 
     } 
    } 

    // set size of JPanel 
    @Override 
    public Dimension getPreferredSize() { 
     if (isPreferredSizeSet()) { 
      return super.getPreferredSize(); 
     } 
     return new Dimension(PREF_W, PREF_H); 
    } 

    private class TimerListener implements ActionListener { 
     @Override 
     public void actionPerformed(ActionEvent e) {    
      // simply iterate through list and move all squares 
      for (Square square : squareList) { 
       square.move(); 
      } 
      repaint(); // then repaint the GUI 
     } 
    } 

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

     JFrame frame = new JFrame("Drawing Panel"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 
} 

// this class does *not* extend JPanel or JComponent 
class Square { 
    public static final int WIDTH = 20; 

    // location of Square 
    private double sqrX; 
    private double sqrY; 

    // X and Y speed 
    private double deltaX; 
    private double deltaY; 

    // width and height of DrawingPanel JPanel 
    private int dpWidth; 
    private int dpHeight; 

    // image to draw 
    private Image image; 

    public Square(Color color, int dpWidth, int dpHeight) { 
     this.dpWidth = dpWidth; 
     this.dpHeight = dpHeight; 

     // create square at random location with random speed 
     sqrX = Math.random() * (dpWidth - WIDTH); 
     sqrY = Math.random() * (dpHeight - WIDTH); 
     deltaX = Math.random() * 10 - 5; 
     deltaY = Math.random() * 10 - 5; 

     // one way to draw it is to create an image and draw it 
     image = new BufferedImage(WIDTH, WIDTH, BufferedImage.TYPE_INT_ARGB); 
     Graphics g = image.getGraphics(); 
     g.setColor(color); 
     g.fillRect(0, 0, WIDTH, WIDTH); 
     g.dispose(); 
    } 

    public void move() { 

     // check that we're not hitting boundaries 
     if (sqrX + deltaX < 0) { 
      deltaX = Math.abs(deltaX); 
     } 
     if (sqrX + deltaX + WIDTH >= dpWidth) { 
      deltaX = -Math.abs(deltaX); 
     } 
     sqrX += deltaX; 

     // check that we're not hitting boundaries 
     if (sqrY + deltaY < 0) { 
      deltaY = Math.abs(deltaY); 
     } 
     if (sqrY + deltaY + WIDTH >= dpHeight) { 
      deltaY = -Math.abs(deltaY); 
     } 
     sqrY += deltaY; 

    } 

    public void draw(Graphics g) { 
     int x = (int) sqrX; 
     int y = (int) sqrY; 
     g.drawImage(image, x, y, null); 
    } 
} 
+0

5.好的,我在方形內部放了一個getPrefferedSize(),但我遇到了一個問題:方塊不是「在一起」,就像它們在單獨的面板上彈起一樣。 – TomCa

+0

@TomCa:看編輯回答 –

+0

哇,非常感謝你!我會仔細研究你的代碼。我不知道你寫的東西的一些,但我想我必須學習這種或那種.. – TomCa