绘制Runnable JPanel

Roi*_*ner 2 java user-interface multithreading repaint paintcomponent

我正在研究这个小型赛马模拟器并且坚持使用它.我希望用户首先选择比赛中的马匹数量(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);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

cam*_*ckr 6

要获得更好的设计,请不要为应用程序使用null布局.使用框架的默认BorderLayout.

  1. 使用所有单选按钮创建JPanel,并将该面板添加到框架的PAGE_START.
  2. 将JButton添加到PAGE_END
  3. 创建一个RaceTrackPane并将您的Horses添加到此面板.此面板可以使用空布局,因为您将移动马匹.此面板已添加到CENTER中.

代码的问题在于如何定义组件的边界并执行自定义绘制:

horse1.setBounds(20, 120, 20, 20);
...
g2d.drawOval(20, 25, 10, 10);
g2d.fillOval(20, 25, 10, 10);
Run Code Online (Sandbox Code Playgroud)

第一个问题是你所有的马都定位在(20,120),所以它们将被涂在彼此之上.

更大的问题是每匹马的大小是(20,20).当你进行绘画时,你会在(20,25)画马,所以它超出了你的组件的大小.尝试使用(0,0,10,10).那就是你应该总是相对于组件的(0,0)进行绘画.然后,您可以通过更改组件的位置来移动组件.

我会考虑使用带有Icon作为你的Horse组件的JLabel,这样你就不必自定义绘画并担心这一切.要获得更高级(但可能更灵活)的解决方案,请查看" 玩形状".