I cannot get this oval to draw on the JFrame.
static JFrame frame = new JFrame("New Frame");
public static void main(String[] args) {
makeframe();
paint(10,10,30,30);
}
//make frame
public static void makeframe(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(375, 300));
frame.getContentPane().add(emptyLabel , BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
// draw oval
public static void paint(int x,int y,int XSIZE,int YSIZE) {
Graphics g = frame.getGraphics();
g.setColor(Color.red);
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
The frame displays but nothing is drawn in it. What am I doing wrong here?
You have created a static method that does not override the paint method. Now others have already pointed out that you need to override paintComponent etc. But for a quick fix you need to do this:
public class MyFrame extends JFrame {
public MyFrame() {
super("My Frame");
// You can set the content pane of the frame to your custom class.
setContentPane(new DrawPane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setVisible(true);
}
// Create a component that you can actually draw on.
class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
g.fillRect(20, 20, 100, 200); // Draw on g here e.g.
}
}
public static void main(String args[]){
new MyFrame();
}
}
However, as someone else pointed out...drawing on a JFrame is very tricky. Better to draw on a JPanel.
Several items come to mind:
Never override paint(), do paintComponent() instead
Why are you drawing on a JFrame directly? Why not extends JComponent (or JPanel) and draw on that instead? it provides more flexibility
What's the purpose of that JLabel? If it sits on top of the JFrame and covers the entire thing then your painting will be hidden behind the label.
The painting code shouldn't rely on the x,y values passed in paint() to determine the drawing routine's start point. paint() is used to paint a section of the component. Draw the oval on the canvas where you want it.
Also, you're not seeing the JLabel because the paint() method is responsible for drawing the component itself as well as child components. Overriding paint() is evil =)
You are overriding the wrong paint() method, you should override the method named paintComponent like this:
#Override
public void paintComponent(Graphics g)
You need to Override an exist paint method that actually up to dates your Frame. In your case you just created your custom new method that is not called by Frame default.
So change your method to this:
public void paint(Graphics g){
}
Related
I watched a tutorial and tried to do same thing, I wrote the codes exactly the same but it shows nothing. I think it is because paintComponent method is not being called, I also tried to print something to console by paintComponent.
Here is my code:
public class Line extends JPanel{
#Override
public void paintComponents(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.drawLine(100, 10, 30, 40);
}
public static void main(String[] args) {
Line l =new Line();
JFrame myFrame = new JFrame("Line");
myFrame.setSize(600, 400);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.add(l);
myFrame.setVisible(true);
}
}
Thank you!
What you want to override is paintComponent, not paintComponents with a s .
paintComponents paints the child components of the current component (well it sort of tells the child components to paint themselves on the Graphics object).
paintComponent paints the component itself, this is the method you want to override to do custom painting for your component.
When I try to draw an oval in JFrame, the paint() method doesn't work, but when I change JFrame to Frame it's fine. Can you please explain this problem?
import java.awt.Graphics;
import java.awt.Window;
import javax.swing.JFrame;
public class Oval extends JFrame
{
public Oval()
{
// this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setSize(400, 400);
}
public void paint(Graphics g)
{
g.drawOval(40, 40, 40, 40);
}
public static void main(String []args)
{
new Oval();
}
}
Don't override paint(). Instead add a JPanel to the JFrame and override paintComponent(g)
Call super method. Even if you override paint() call super.paint() (Of course it's better to use paintComponnet())
Well you shouldn't override the paint() method, instead add a JPanel to your JFrame and override the JPanel's paintComponent() method and draw your stuff on the JPanel instead.
Here's a demonstration:
import javax.swing.*;
import java.awt.*;
public class Oval extends JFrame
{
public Oval()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new GridBagLayout());
OvalPanel ovalPanel = new OvalPanel(100); // SIZE of oval is 100
ovalPanel.setPreferredSize(new Dimension(400, 400));
add(ovalPanel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new Oval();
}
});
}
}
class OvalPanel extends JPanel
{
private final int SIZE;
public OvalPanel(final int size)
{
this.SIZE = size;
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g); // Call the super class's paintComponent so that it does its appropriate rendering first.
g.drawOval((getWidth() - SIZE) >> 1, (getHeight() - SIZE) >> 1, SIZE, SIZE); // Center the oval
}
}
Also if you notice, I used SwingUtlities.invokeLater() method and there I called the Oval constructor. That I did because Swing is thread unsafe and so you should call any Swing related methods in the Event Dispatcher Thread which is responsible for handling any Swing related stuff, and that's what the invokeLater() method does.
Note: if you're using JDK 8, you can write the SwingUtilities.invokeLater() statement as:
SwingUtilities.invokeLater(Oval::new); // That's JDK 8 Method reference feature.
You might wonder as to why you shouldn't do stuff directly in the paint() method. The reason has to do with the way paint() method is called. You see, the RepaintManager is responsible for handling the painting of all the Swing based components, and when the paint() method is called, it in turn calls the paintComponent(), paintChildren() and paintBorder() methods. paintComponent() is the best place to handle any component based rendering and that's why its the suggestion. Though, even the following code works:
import javax.swing.*;
import java.awt.*;
public class Oval extends JFrame
{
public Oval()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(400, 400);
setLocationRelativeTo(null);
setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g); // Calling the super class's paint method first.
// so that it handles its rendering.
g.drawOval(40, 40, 40, 40);
}
public static void main(String[] args)
{
new Oval();
}
}
Even the order in which methods are called is important in Swing. Like:
setSize(400, 400); // Setting the size of JFrame first.
setLocationRelativeTo(null); // Locating the JFrame based on its size then.
setVisible(true); // Finally its made visible
All the above work as expected. But the following won't display the results properly:
setVisible(true); // JFrame is already made visible
setLocationRelativeTo(null); // This first locates the JFrame based on its (0, 0) size
setSize(400, 400); // Then its size is increased. Not as expected as the JFrame appears shifted from center.
So I have two classes, one is in charge of creating the JPanel and also overrides paint. The other contains the main and uses this other class. For the sake of ease, I've cut out what isn't involved in graphics. This first one does the JPanel and paint. The second is the main. I apologize for any poor structure or mess, I'm relatively new and I've just been throwing things in to see what works. The stuff in the paint is only a test, it isn't the primary goal.
public class PokerTable extends JPanel {
private static final int WIDTH = 800;
private static final int HEIGHT = WIDTH * 3 / 4;
private static final String NAME = "Test";
private JFrame frame = new JFrame(NAME);
public PokerTable() {
//frame.setMinimumSize(new Dimension(WIDTH,HEIGHT));
//frame.setMaximumSize(new Dimension(WIDTH,HEIGHT));
frame.setPreferredSize(new Dimension(WIDTH,HEIGHT));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setBackground(Color.GREEN);
g2d.setColor(Color.RED);
g2d.fillOval(0, 0, 30, 30);
}
}
This next one does more than call the PokerTable, but I've left the other parts out as they rely on other classes and just print to console.
public class Poker{
public static void main(String[]args) {
System.out.println("hello");
PokerTable pt = new PokerTable();
pt.repaint();
}
Not that I necessarily expected it to work, I've changed the extension on PokerTable to Canvas and JFrame without any luck.
You're not adding the panel to the frame, try with:
frame.add(this);
in PokerTable constructor
You need to add the panel to the frame, or the panel will never repaint.
frame.add(panel) or frame.add(this)
is what you need to call depending on where you do it.
Also, you should be overriding paintComponent, and never paint directly. that won't cause your code to fail, but it is bad practice.
I have an assignment to create a paint program in Java. I have managed to create something but not exactly what I wanted.
My problem is that I cannot create a JFrame in my IDE(NetBeans 7.0.1) from the options that the IDE gives me, and call the paint classes correctly.
To be more specific I want to press a button from one panel(ex. Panel1) and paint in Panel2,in the same frame.
That's the calling of the class:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
PaintFlower102 f = new PaintFlower102();
}
Part of Class:
super("Drag to Paint");
getContentPane().add(new Label ("Click and Drag"),BorderLayout.SOUTH);
// add(new JButton("Brush 20"),BorderLayout.NORTH);
addMouseMotionListener( new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent event) {
xval=event.getX();
yval=event.getY();
repaint();
}
});
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(PaintFlower102.DISPOSE_ON_CLOSE);
}
public void paint(Graphics g) {
g.fillOval(xval, yval, 10, 10);
}
The problem is that if I do not put the extend JFrame in the class this doesn't work. And if I do, it creates a new frame in which I can draw.
Suggestions:
Don't ever paint directly in a JFrame except under rare circumstances of absolute need (this isn't one of them).
Instead paint in a JPanel or JComponent or other derivative of JComponent.
Paint in the class's paintComponent(Graphics g) method, not in paint(Graphics g).
Read the Java tutorials on this as it's all explained well there. Check out Trail: 2D Graphics and Performing Custom Painting.
I might be wrong, but I think that you need to include super.paintComponent(g), and override the paintComponent method like Hovercraft Full Of Eels said.
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw Oval
g.fillOval(xval, yval, 10, 10);
}
How can I tell the paint method to draw background on JPanel only and not on the entire JFrame.
My JFrame size is bigger than the JPanel. When I try to paint a grid background for the JPanel, the grid seems to be painted all over the JFrame instead of just the JPanel.
Here parts of the code:
public class Drawing extends JFrame {
JPanel drawingPanel;
...........
public Drawing (){
drawingPanel = new JPanel();
drawingPanel.setPreferredSize(new Dimension(600,600));
}
public void paint(Graphics g)
{
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
paintBackground(g2); //call a METHOD to paint the for JPANEL
}
private void paintBackground(Graphics2D g2)
{
g2.setPaint(Color.GRAY);
for (int i = 0; i < drawingPanel.getSize().width; i += 300)
{
Shape line = new Line2D.Float(i, 0, i, drawingPanel.getSize().height);
g2.draw(line);
}
for (int i = 0; i < drawingPanel.getSize().height; i += 300)
{
Shape line = new Line2D.Float(0, i, drawingPanel.getSize().width, i);
g2.draw(line);
}
} //END private void paintBackground(Graphics2D g2)
}
If you want to do painting on the JPanel then override the JPanel, not the JFrame.
You should be overriding the paintComponent() method of JPanel. Read the section from the Swing tutorial on Custom Painting for a working example.
camickr is correct. So:
public class Drawing extends JFrame {
JPanel drawingPanel;
...........
public Drawing (){
drawingPanel = new MyPanel();
drawingPanel.setPreferredSize(new Dimension(600,600));
add(drawingPanel);
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
myBackgroundRoutine(g2);
}
}
You need to strictly separate your drawing from different components. Swing is already
managing subcomponents, so there is absolutely no need to implement drawings in your
Panel in the Frame (calling paintComponents() is a severe error).
And you should never override paint(), because only paintComponent()
is used in Swing. Don't mix both until you absolutely know what you are doing.
super.paintComponents(g);
I would suggest as your first point of investigation.
The code you posted is not complete, it's missing how the panel is added to the JFrame and which LayoutManager is being used.
The code seams to be correct. Are you sure the JPanel is not occupying the whole JFrame? Add a System.out.println(drawingPanel.getSize()) to check this.
If you are using the BorderLayout, the default for JFrame, and has just added the panel without any constraint, the panel will use the whole area. The PreferredSize is ignored.
Try this, just for testing:
public Drawing (){
drawingPanel = new JPanel();
drawingPanel.setPreferredSize(new Dimension(600,600)); // ignored
drawingPanel.setBounds(0, 0, 600, 600); // location and size
setLayout(null);
add(drawingPanel);
}
but IMO this is not the best or correct way to do it. I would prefer to override the paintComponent() method from the JPanel, as suggested by Thorsten and camickr.
But it will still use the whole area of the JFrame until other Component is added to the JFrame or the LayoutManager changed.
You should override the JPanel, not the JFrame to do painting. You can override the paintComponent() method of the JPanel