我正在研究这款小型赛马模拟器并且坚持使用它。我希望用户首先选择比赛中的马匹数量(2-6),然后单击“开始”按钮。然后,我想绘制/绘制赛道和马(由圆圈表示)。出于某种原因,当代码到达创建Horse实例的点时,它永远不会被绘制到框架中。 下面是代码。我错过了什么?
Main.java:
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
RaceTrack myRace = new RaceTrack();
myRace.setVisible(true);
}
});
}
}
RaceTrack.java:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.Border;
public class RaceTrack extends JFrame implements Runnable {
public RaceTrack() {
initUI();
}
public static int selectedRaceSize = 2;
private void initUI() {
final Container pane = getContentPane();
String horseNum[] = { "2", "3", "4", "5", "6" };
JPanel buttonPanel = new JPanel();
Border border = BorderFactory.createTitledBorder("Please select number of horses:");
buttonPanel.setBorder(border);
ButtonGroup buttonGroup = new ButtonGroup();
JRadioButton aRadioButton;
// For each String passed in:
// Create button, add to panel, and add to group
for (int i = 0, n = horseNum.length; i < n; i++) {
if (i == 0) {
// Default selection
aRadioButton = new JRadioButton(horseNum[i], true);
} else {
aRadioButton = new JRadioButton(horseNum[i]);
}
buttonPanel.add(aRadioButton);
buttonGroup.add(aRadioButton);
}
pane.add(buttonPanel, BorderLayout.PAGE_START);
final JPanel raceTrackPanel = new JPanel(null);
final JButton startButton = new JButton("Start!");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
startButton.setEnabled(false);
Horse horse1 = new Horse("horse1");
raceTrackPanel.add(horse1);
pane.add(raceTrackPanel, BorderLayout.CENTER);
repaint();
}
});
pane.add(startButton, BorderLayout.PAGE_END);
startButton.setBounds(50, 200, 300, 30);
setTitle("Horse Race v1.0");
setSize(400, 300);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
@Override
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
Horse.java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Horse extends JPanel implements Runnable {
Thread runner;
public Horse() {
}
public Horse(String threadName) {
runner = new Thread(this, threadName);
runner.start();
}
public void run() {
this.repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(252, 211, 61));
g2d.drawOval(20, 25, 10, 10);
g2d.fillOval(20, 25, 10, 10);
}
}
答案 0 :(得分:6)
要获得更好的设计,请不要为应用程序使用null布局。使用框架的默认BorderLayout。
代码的问题在于如何定义组件的边界并执行自定义绘制:
horse1.setBounds(20, 120, 20, 20);
...
g2d.drawOval(20, 25, 10, 10);
g2d.fillOval(20, 25, 10, 10);
第一个问题是你所有的马都位于(20,120),因此它们将被涂在彼此之上。
更大的问题是每匹马的大小是(20,20)。当你进行绘画时,你会在(20,25)画马,所以它超出了你的组件的大小。尝试使用(0,0,10,10)。那就是你应该总是相对于组件的(0,0)进行绘画。然后,通过更改组件的位置来移动组件。
我会考虑使用带有Icon的JLabel作为您的Horse组件,这样您就不必进行自定义绘画并担心所有这些。要获得更高级(但可能更灵活)的解决方案,请查看Playing With Shapes。
答案 1 :(得分:3)
我错过了什么?
您缺少数据模型。你正试图在视图中做所有事情。
该视图用于显示模型中的数据。
你的Horse课程看起来应该更像这样:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;
public class Horse {
public static final int RADIUS = 15;
public static final int MARGIN = 15;
public static final int DIAMETER = RADIUS + RADIUS;
public static final int POSITION = DIAMETER + MARGIN;
private static Point currentPosition;
static {
int x = MARGIN + RADIUS;
int y = MARGIN + RADIUS;
currentPosition = new Point(x, y);
}
private static Random random = new Random();
/** Distance in pixels */
private double distance;
/** Velocity in pixels per second */
private int velocity;
private Color color;
/** Initial position in pixels */
private Point initialPosition;
private String name;
public Horse(Color color, String name) {
setInitialPosition();
this.color = color;
this.name = name;
init();
}
private void setInitialPosition() {
this.initialPosition =
new Point(currentPosition.x, currentPosition.y);
currentPosition.y += POSITION;
}
public void init() {
this.distance = 0.0D;
}
public void setVelocity() {
this.velocity = random.nextInt(5) + 6;
}
public double getDistance() {
return distance;
}
public String getName() {
return name;
}
public void moveHorse(int milliseconds) {
double pixels = 0.001D * velocity * milliseconds;
this.distance += pixels;
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(initialPosition.x + (int) Math.round(distance) - RADIUS,
initialPosition.y - RADIUS, DIAMETER, DIAMETER);
}
}
该类中的最后一个方法是draw。创建动画时,如果对象自行绘制,则会更容易。
这是一个种族课程。
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class Race {
/** Distance of race in pixels */
private double distance;
private long elapsedTime;
private List<Horse> horses;
public Race(double distance) {
this.distance = distance;
this.horses = new ArrayList<Horse>();
this.elapsedTime = 0;
}
public void init() {
this.elapsedTime = 0;
for (Horse horse : horses) {
horse.init();
}
}
public void addHorse(Horse horse) {
this.horses.add(horse);
}
public int getHorseCount() {
return horses.size();
}
public double getDistance() {
return distance;
}
public void setElapsedTime(long elapsedTime) {
if (isWinner() == null) {
this.elapsedTime = elapsedTime;
}
}
public String getElapsedTime() {
int centiseconds = (int) (((elapsedTime % 1000L) + 5L) / 10L);
int seconds = (int) (elapsedTime / 1000L);
if (seconds < 60) {
return String.format("%2d.%02d", seconds, centiseconds);
} else {
int minutes = seconds / 60;
seconds -= minutes * 60;
return String.format("%2d:%02d.%02d", minutes, seconds,
centiseconds);
}
}
public int getTrackWidth() {
return (int) Math.round(getDistance()) + 100;
}
public int getTrackHeight() {
return getHorseCount() * Horse.POSITION + Horse.MARGIN;
}
public void setHorseVelocity() {
for (Horse horse : horses) {
horse.setVelocity();
}
}
public void updateHorsePositions(int milliseconds) {
for (Horse horse : horses) {
horse.moveHorse(milliseconds);
}
}
public Horse isWinner() {
for (Horse horse : horses) {
if ((distance - Horse.RADIUS) <= horse.getDistance()) {
return horse;
}
}
return null;
}
public boolean allHorsesRunning() {
for (Horse horse : horses) {
if ((distance + Horse.RADIUS + 6) > horse.getDistance()) {
return true;
}
}
return false;
}
public void draw(Graphics g) {
drawLine(g, Horse.POSITION, 6);
drawLine(g, (int) Math.round(getDistance()) + Horse.RADIUS
+ Horse.MARGIN, 6);
for (Horse horse : horses) {
horse.draw(g);
}
}
private void drawLine(Graphics g, int x, int width) {
int y = Horse.MARGIN;
int height = getHorseCount() * Horse.POSITION - y;
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
}
再次,绘制方法吸引了比赛。
那么,你实际绘制的JPanel会是什么样的?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
import com.ggl.horse.race.model.Race;
public class RacePanel extends JPanel {
private static final long serialVersionUID = 1040577191811714944L;
private Race race;
public RacePanel(Race race) {
this.race = race;
int width = race.getTrackWidth();
int height = race.getTrackHeight();
this.setPreferredSize(new Dimension(width, height));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawBackground(g);
race.draw(g);
}
private void drawBackground(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
视图并不关心是否有一匹马,三匹马或10匹马。视图不会改变。
仅模型更改。
这应该是足以帮助您入门的信息。