问题
I'm trying to draw simple shapes with Canvas, in this class I've set the painting
public class Game extends Canvas{
//FIELDS
public int WIDTH = 1024;
public int HEIGHT = WIDTH / 16 * 9;
//METHODS
public void start(){
Dimension size = new Dimension (WIDTH, HEIGHT);
setPreferredSize(size);
paint(null);
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillOval(100, 100, 30, 30);
}
}
And in this the Window
public class MainW {
public static void main(String[] args) {
Game ga = new Game();
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(ga);
frame.setVisible(true);
ga.start();
}
}
It works, but the JFrame is not adapting to the Canvas. I have to manually resize the window to see the objects. How can I pack it so that JFrame automatically encompasses the Canvas?
EDIT: That's really weird. While frame.pack() is indeed essential, it's not enough. What I did was change the start method and turn it into a constructor, like that:
public class Game extends Canvas{
//FIELDS
public int WIDTH = 1024;
public int HEIGHT = WIDTH / 16 * 9;
//METHODS
public void Game(){
Dimension size = new Dimension (WIDTH, HEIGHT);
setPreferredSize(size);
}
then, from the other class, Eclipse complained about calling the constructor directly(E.G. ga.Game), so I followed it's tip and changed to:
public static void main(String[] args) {
Game ga = new Game();
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(ga);
frame.setVisible(true);
ga.getName();
}
This way I achieve what I have in mind but I really don't know why I can't call the constructor.
回答1:
I don't know what it is you're trying to do, but you should NEVER be calling paint
and especially not pass it null
.
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing for details about how painting works.
In order to get the window to size to you component, you need to provide it some important information.
While Window#pack
is the method you are looking for, it will not help you unless you provide appropriate sizing hints.
In this case, you need to override the getPreferredSize
method of you component and provide an appropriate size value. Window#pack
will use this value to determine what size it needs to be in order to accommodate it.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestPaint {
public static void main(String[] args) {
new TestPaint();
}
public TestPaint() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillOval(100, 100, 30, 30);
}
}
}
The paint chain is very important and you should avoid breaking it at all coasts. Make sure you always call super.paintXxx
or be prepared for some serious weirdness
Also may want to have a read of Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
回答2:
Use java.awt.Window.pack (JFrame
indirectly extends Window
):
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents.
// ...
frame.add(ga);
frame.pack();
frame.setVisible(true);
// ...
回答3:
After painting on canvas try repaint the JFrame
public static void main(String[] args) {
Game ga = new Game();
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(ga);
frame.setVisible(true);
ga.start();
//repaint here
frame.repaint();
}
Also note that:
frame.pack
for fixing the size issue.
frame.revalidate
sometimes help when adding or removing components in runtime.
来源:https://stackoverflow.com/questions/17922443/drawing-canvas-on-jframe