将绘图添加到面板
Add drawing to a Panel
这应该很简单,但我做不到。
我有两个 classes,一个应该画一个圆圈,另一个用按钮设置框架和面板。单击按钮时,框架上应出现一个圆圈。我很困惑为什么它没有出现。抱歉,这可能很简单。
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);
}
}
和球class:
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 将首先绘制最后添加的组件。所以球被涂上了,然后空面板被涂在上面。
摆脱面板,它没有用。
编辑:
出于某种原因,我认为您在单击按钮时将球添加到框架而不是面板。
如果您确实将 Ball 直接添加到框架中,我上面的解释是正确的。
但是,我的解释是不正确的,因为您在 ActionListener 中的代码确实将 Ball 添加到面板中。正确的解释如下。
当您将 Ball 添加到面板时,您看不到 Ball,因为默认情况下 JPanel 使用 FlowLayout 并且 FlowLayout 遵循添加到它的任何组件的首选大小。你没有实现 getPreferredSize()
方法所以大小是 (0, 0) 所以没有什么可画的。
因此,如果您确实在 Ball class 中实施了 getPreferredSize()
方法,则 Ball 将显示在面板上。此外,每次单击按钮时,您都可以显示一个新球。
正如 camickr 回答的那样,您需要 revalidate()
(或同时调用 invalidate()
和 validate()
,两者都可以),然后 repaint()
面板。
无效方法将面板标记为“'incorrect'”;基本上标记它以供检查。
Validate 执行组件的布局。
Revalidate 两者都执行,但是,validate 是同步的,而 revalidate 不是。
验证面板后,您需要调用重绘来重绘该面板。
作为旁注,JavaFX is replacing 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);
}
}
这应该很简单,但我做不到。
我有两个 classes,一个应该画一个圆圈,另一个用按钮设置框架和面板。单击按钮时,框架上应出现一个圆圈。我很困惑为什么它没有出现。抱歉,这可能很简单。
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);
}
}
和球class:
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 将首先绘制最后添加的组件。所以球被涂上了,然后空面板被涂在上面。
摆脱面板,它没有用。
编辑:
出于某种原因,我认为您在单击按钮时将球添加到框架而不是面板。
如果您确实将 Ball 直接添加到框架中,我上面的解释是正确的。
但是,我的解释是不正确的,因为您在 ActionListener 中的代码确实将 Ball 添加到面板中。正确的解释如下。
当您将 Ball 添加到面板时,您看不到 Ball,因为默认情况下 JPanel 使用 FlowLayout 并且 FlowLayout 遵循添加到它的任何组件的首选大小。你没有实现 getPreferredSize()
方法所以大小是 (0, 0) 所以没有什么可画的。
因此,如果您确实在 Ball class 中实施了 getPreferredSize()
方法,则 Ball 将显示在面板上。此外,每次单击按钮时,您都可以显示一个新球。
正如 camickr 回答的那样,您需要 revalidate()
(或同时调用 invalidate()
和 validate()
,两者都可以),然后 repaint()
面板。
无效方法将面板标记为“'incorrect'”;基本上标记它以供检查。
Validate 执行组件的布局。
Revalidate 两者都执行,但是,validate 是同步的,而 revalidate 不是。
验证面板后,您需要调用重绘来重绘该面板。
作为旁注,JavaFX is replacing 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);
}
}