2017-01-07 6 views
0

Ich habe eine App erstellt, die ein Quadrat enthält, das jedes Mal springt, wenn es eine Kante des Rahmens berührt.Ich habe keine Probleme beim Mittagessen der App, das Problem ist, dass ich nicht weiß, wie man verschiedene Threads erstellen kann Vielfache Quadrate innerhalb des Rahmens. Ich habe mehrere Dinge ausprobiert, aber ich kann nicht herausfinden, wo ich die Threads erstellen soll. Ich bemerkte auch, dass das Quadrat nur sichtbar ist, wenn ich es direkt im Rahmen hinzufüge und nicht, wenn ich es in ein JPanel stecke.Wie Multithread mit 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); 
} 
} 

Ist es normal, dass trotz ich eine Zeit von 2 innerhalb der Timer setzen, die Platz bewegt sich sehr langsam?

+0

Vielen you.I die x_y_rules put() Methode innerhalb des ActionListener.The Problem ist, dass, wenn eine andere Platz schaffen und ich es mit dem Rahmen hinzufügen Letzteres zeigt nur ein Quadrat. Deshalb dachte ich, ich sollte Threads verwenden. – TomCa

+0

Sie sollten die Layout-Manager untersuchen, da Sie Threading nicht zum Lösen eines Layout-Manager-Problems verwenden. JFrame contentPane verwendet BorderLayout, und wenn Sie dem JFrame standardmäßig eine Komponente hinzufügen, wird nur die zuletzt hinzugefügte Komponente angezeigt. –

Antwort

2

Probleme:

  1. Sie Programmlogik haben, die x_y_rules() Call-Methode, innerhalb der Methode paintcomponent. Holen Sie es raus, da es nicht dorthin gehört, und legen Sie es stattdessen in den ActionListener-Code des Timers, wo es hingehört.
  2. können Sie jedem Square einen eigenen Swing Timer geben, wenn Sie möchten. Dies ist nicht wirklich ein Threading-Problem, da der ActionListener jedes Timers auf dem EDT läuft.
  3. Zwei Millisekunden ist eine unrealistische Zeitscheibe zu erwarten in einem Swing-Timer zu verwenden und kein Timer wird so schnell ausgeführt werden. 11 bis 13 ist etwa das schnellste zu erwarten oder zu hoffen.
  4. Wenn Sie möchten, dass sich Ihr Sprite schneller bewegt, geben Sie ihm einen höheren Wert für delta-x und delta-y in Ihrem Bewegungscode.
  5. Ihre JComponent hat keine bevorzugte Größe definiert, was wahrscheinlich ist, warum sie nicht im JPanel angezeigt wird, da das Standard-FlowLayout es dann auf [0, 0] setzt. Überschreiben Sie die getPreferredSize() und lassen Sie sie einen angemessenen Dimensionswert zurückgeben.
  6. Sie rufen setVisible(true) auf Ihrem JFrame vor dem Hinzufügen aller Komponenten, ein No-No.

Ok, ich eine getPrefferedSize put() im Quadrat Klasse, aber ich habe ein Problem festgestellt: Die Plätze sind nicht „zusammen“, dann ist es, wie sie auf getrennten Platten

sind Prellen

Dann ist Ihr Programm Struktur ist defekt. Sie möchten wirklich keine separaten Swing-Komponenten erstellen, und in der Tat sollte Ihre Square-Klasse JComponent oder JPanel nicht erweitern. Vielmehr

  • Platz soll eine logischen Klasse sein, eine, die aus dem Nichts (anders als Standard-Object) erstreckt.
  • es Gib ein Ziehverfahren, sagen public void draw(Graphics g) {....}
  • eine Klasse erstellen, die JPanel erweitert, sagen DrawingPanel genannt, und seine Methode paintcomponent außer Kraft setzen.
  • Weisen Sie der DrawingPanel-Klasse ArrayList<Square> zu, damit sie mehrere Square-Objekte aufnehmen kann.
  • Geben Sie die DrawingPanel Klasse einen Swing-Timer
  • In der Timer der DrawingPanel Klasse, sie haben die Position aller Plätze in der Arraylist aktualisieren, und rufen Sie dann repaint()
  • In der paintcomponent Methode, durchläuft alle Plätze in die Liste, mit einer for-Schleife, und rufen Sie jedes Zeichen-Methode.

Zum Beispiel:

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. Ok, ich habe eine getPreferedSize() in die Square-Klasse eingefügt, aber ich habe ein Problem festgestellt: die Quadrate sind nicht "zusammen", es ist, als würden sie auf separaten Panels hüpfen. – TomCa

+0

@TomCa: siehe bearbeiten, um zu antworten –

+0

Wow, vielen Dank! Ich werde Ihren Code sorgfältig studieren.Ich weiß nicht, was Sie geschrieben haben, aber ich denke, ich muss auf die eine oder andere Weise lernen .. – TomCa