这应该是足够简单,但我不能使它工作。
我有两个类,一个应该画一个圆圈,另一个设置一个框架和一个按钮面板。点击按钮后,框架上会出现一个圆圈。我很困惑为什么它没有出现。可能很简单,抱歉。
package ballsOnPane;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display implements ActionListener{
private JFrame frame;
private JPanel panel;
private JButton button;
public static void main(String[] args) {
Display display = new Display();
}
public Display() {
frame = new JFrame();
frame.setSize(800, 500);
frame.setTitle("Show balls");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
panel = new JPanel();
frame.add(panel, BorderLayout.CENTER);
button = new JButton("New Ball");
frame.add(button, BorderLayout.SOUTH);
button.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
Ball ball = new Ball(100, 100, 50);
panel.add(ball);
}
}
和球类:
package ballsOnPane;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class Ball extends JPanel{
private int x;
private int y;
private int r;
public Ball(int x, int y, int r){
this.x = x;
this.y = y;
this.r = r;
}
public void paintComponent(Graphics g) {
Graphics2D g2 =(Graphics2D) g;
Ellipse2D circ = new Ellipse2D.Float(x, y, r, r);
g2.draw(circ);
}
}
当您向可见GUI添加组件时,基本代码是:
panel.add(...);
panel.revalidate(); // to invoke the layout manager
panel.repaint(); // to repaint the components
否则,添加的组件的大小为(0,0),因此没有什么可绘制的。按钮也是如此。它应该在框架可见之前添加,或者您也需要执行revalidate()/repaint()。
在这种情况下,你还有第二个问题:
frame.add(panel, BorderLayout.CENTER);
首先你在BorderLayout的中心添加一个空面板,然后当你点击按钮时,你将球添加到中心。
Swing将首先绘制最后添加的组件。所以球被涂上颜色,然后空面板被涂在上面。
去掉面板,它没有用。
编辑:由于某些原因,当你点击按钮时,我以为你是在将球添加到框架中,而不是添加到面板中。
我上面的解释是正确的,如果你真的把球直接添加到框架中。
然而,我的解释是不正确的,因为你在ActionListener中的代码确实将球添加到面板。正确的解释如下。
当你将小球添加到面板时,你看不到小球,因为默认情况下JPanel使用FlowLayout,而FlowLayout尊重添加到它的任何组件的首选大小。你没有实现getPreferredSize()
方法,所以尺寸是(0,0),所以没有什么可以绘制的。
所以如果你实现getPreferredSize()
方法在你的球类球将显示在面板上。此外,每次单击按钮时,您都可以显示一个新的Ball。
如果camickr接听,您需要拨打revalidate()
(或同时拨打invalidate()
&validate()
,两者都将工作),然后repaint()
面板。
invalidate方法将面板标记为"不正确";基本上是标记供检查。
Validate执行组件的布局。
Revalidate两者都做,但是validate是同步的,而Revalidate不是。
验证面板后,需要调用repaint来重新绘制该面板。
作为旁注,JavaFX正在取代Swing/AWT,在我看来,它更容易使用。你也许想调查一下。:)
一个简短的代码示例,在JavaFX中做类似于您当前正在做的事情:
public class test extends Application{
Scene scene;
@Override
public void start(Stage primaryStage) throws Exception{
StackPane root = new StackPane();
root.setBackground(
new Background(new BackgroundFill(Color.ALICEBLUE,null,null)));
Button begin = new Button("Add Circle");
begin.setOnAction((ActionEvent e)->{
Circle c = new Circle(200,200,100,Color.RED);
root.getChildren().add(c);
});
root.getChildren().add(begin);
scene = new Scene(root, 700, 700);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}