paint(Graphics g) prevents Components from being drawn - java

I have created a testing version to simplify the problem that I'm having for you guys:
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
JLabel l = new JLabel("hello");
JPanel cp;
public Test(){
setContentPane(cp = new JPanel());
cp.add(l);
setSize(200, 200);
setVisible(true);
}
public void paint(Graphics g){
//do absolutely nothing
}
}
When you start up the program, you get to see a perfectly blank window. However, if you remove the paint method, the JLabel shows up! (I've had to search for this bug for ages, really). Now, how can I enable a window to both use graphics and regularly draw components?
Thanks in advance

1) You should not override paint(..) of JFrame, unless you have a specific purpose for that.
The correct method of drawing in Swing is to:
Add a JPanel to JFrame
in JPanel, override paintComponent(..) and getPreferredSize() to return correct Dimensions which fit our drawing.
NB dont forget to call super.paintComponent(g) as first call in overridden paintComponent method as to honor the paint chain
See this answer of mine which has a few examples for you.
Also do not extend JFrame unnecessarilly.
Dont call setSize on JFrame rather use a correct LayoutManager and/or override getPreferredSize() - usually done on a JPanel when we are drawing directly or the JPanel will have no size if no components are added, if they are it will only be as big as it needs to fit the components and not the image.
and than call pack() on JFrame before setting it visible.
And just incase have a look Concurrency in Swing especially Event-Dispatch-Thread

Related

error "The method setDefaultCloseOperation(int) is undefined for the type Frame"

I am using Visual Studio Code 2020, and it is giving me the error "The method setDefaultCloseOperation(int) is undefined for the type Frame"
The problem is line 52,
import java.awt.Frame;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import java.awt.Color;
public class Main {
public static void main(String[] args) {
boolean loop = false;
/* while (loop = true) {
try {
Thread.sleep(2000);
} catch (InterruptedException reallyIgnored) {}
System.out.println("Loop is working.");
} */
}
static class GraphicsEngine extends Component {
public void paint(Graphics g) {
// Creating Graphics Shortcut
Graphics2D g2d = (Graphics2D)g;
// Creating new framw window, declaring size
Frame frame = new Frame();
frame.add(new GraphicsEngine());
int frameWidth = 700;
int frameHeight = 500;
frame.setSize(frameWidth, frameHeight);
frame.setLayout(null);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
/* Next part will create dot that moves across screen.
It will have a loop that draws the dot, and also a loop
that erases the previous dot. */
g2d.SetColor(new Color(255, 255, 255));
g2d.fillRect(0, 0, getSize().height-1, getSize().height-1);
}
}
}
I have tried looking for answers, but none of the ones I found had worked.
I am a noob, and picked up java a few days ago. I don't really understand much, but I am trying to learn how graphics work right now
The error means that the setDefaultCloseOperation(int) is not found as a method of your object frame . This could be because there is no method with that name in the frame object, or if there is such a method, there isn't one that takes a single int argument.
Looking up the API here for Frame and JFrame:
https://docs.oracle.com/javase/7/docs/api/java/awt/Frame.html https://docs.oracle.com/javase/7/docs/api/javax/swing/JFrame.html
setDeaultCloseOperation seems to be defined for the JFrame object, and not Frame. JFrame extends Frame, meaning it is a specific kind of frame. Specifically, it is a frame that has the setDefaultOperation() method.
Perhaps change your frame definition to Frame frame = new JFrame();
or JFrame frame = new JFrame();
Your tag says you are asking about a JFrame, which does have the setDefaultCloseOperation(...) method.
However, your code is using Frame which is an AWT component, not a Swing component. Use a JFrame for Swing.
Also, you class is extending Canvas. For a Swing application you should be extending JPanel and overriding paintComponent().
There is no need to use AWT components when you can use Swing.
I am trying to learn how graphics work right now
First of all you should NEVER create a component in a painting method. A painting method should only use the Graphics object to do painting.
Read the section from the Swing tutorial on Custom Painting for working examples to get you started.
Follow the examples from the tutorial for properly structured code. The code you posted here is mostly wrong.

Cant draw two items to Jframe

I cant Draw two items( there will be more) to a Jframe, im trying to make a landscape, but the item painted last overwrites anything before it.
Main:
import javax.swing.*;
import java.awt.*;
public class TheComponets extends JComponent {
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(600, 600);
frame.setTitle("A house on the water!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
House home = new House();
Sun sun = new Sun();
frame.setLayout(new GridLayout(2,3));
frame.add(home);
frame.add(sun);
}
}
House class:
import javax.swing.*;
import java.awt.*;
import java.applet.*;
// Program to draw a house
public class House extends JComponent
{
public void paintComponent(Graphics g)
{
// Draw the roof
g.setColor(Color.red);
int xs[] = {100,160,220};
int ys[] = {100,50,100};
Polygon poly=new Polygon(xs,ys,3);
g.fillPolygon(poly);
// Draw the body of house
g.setColor(Color.blue);
g.fillRect(100,100,120,120);
// draw the door
g.setColor(Color.orange);
g.fillRect(145,160,30,60);
}
}
Sun class:
import javax.swing.*;
import java.awt.*;
public class Sun extends JComponent {
public void paintComponent(Graphics g)
{
// draw sun
g.setColor(Color.yellow);
g.fillOval(500, 0, 50, 50);
}
}
I want the house and the sun to show up in the Jframe, but as of now it will only show the last frame.add() object. I have only been programming for two months and dont know much about Swing and awt. Please try to keep that in mind when answering.
The reason of this, is that a JFrame uses a BorderLayout by default. When you frame.add(component) without any constraints, the component will be added to BorderLayout.CENTER position. So, no matter how many components you will add without constraints, borderlayout will override the older since all of them are being added to CENTER.
The solution would be either to choose where you want your components to be added:
frame.add(home,BorderLayout.CENTER);
frame.add(sun,BorderLayout.LINE_START);
either to change the layout of your container (the JFrame in your case):
frame.setLayout(new FlowLayout());
frame.add(home);
frame.add(sun);
Worth to read: A Visual Guide to Layout Managers
Finally, do not #Override paint() method. #Override paintComponent() method instead.
When you use individual panels for custom painting then your painting will be done in 2D since components are positioned in 2D space based on the layout manager used.
im trying to make a landscape,
Then keep all you custom painting in a single class.
First you paint the background. Then you paint the sun, then the house etc.
You will now have full control over the order in which items are painted.
To Add multiple components on JFrame, need to set layout from Layout manager. it can be FlowLayout or Gridlayout or BorderLayout....
In your case,it add Last component only because JFrame's default layout is BoderLayout and can add component
frame.add(home, BorderLayout.LINE_START);
you have PAGE_START, PAGE_END, LINE_START, LINE_END, CENTER position to add component. so add second component to other position or change layout of frame using
frame.setLayout(new FlowLayout());

Add GUI with Swing, but unsure of the sequence to take

I'm building a GUI for a data processing algorithm. I can instantiate the window, give it a background, title, etc., but when I try adding panels to it, I run into trouble. What I'm really looking for more than a proofreader is a suggestion for the sequence in which to build, configure, and add objects in Java Swing so that they behave correctly, in a generic sense. So, is this the best way to build a JFrame with a different-colored panel in it?
Declare JFrame
Set JFrame color (background color)
Declare JPanel (box to represent data graphically)
Set JPanel color (box color)
Add JPanel to JFrame
Set JFrame to visible = true
It makes sense intuitively but it doesn't seem to work, no matter what I do. I've found step-by-step instructions elsewhere but they tend to explain what to type more than why you're typing it, so you get a very narrow understanding of what's going on. Thanks for any help!
Below is the full code; I hesitated to post it because I'd begun experimenting with Graphics2D and it isn't well-commented, but if it helps:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class GUI extends JFrame
{
JFrame mainWindow = new JFrame();
JPanel backgroundPanel = new JPanel();
JPanel subPanel = new JPanel();
Color background = new Color(40,40,40);
Color subWindow = new Color(255, 255, 255);
TitledBorder title = BorderFactory.createTitledBorder("title");
Rectangle rect1 = new Rectangle(10, 10, 40, 40);
Graphics2D g;
public static void main (String[] args)
{
new GUI();
}
public GUI()
{
initializeGUI();
}
private void initializeGUI()
{
mainWindow.setSize(1340, 880);
backgroundPanel.setBackground(background);
subPanel.setBackground(subWindow);
subPanel.setBorder(title);
mainWindow.setTitle("Ed");
mainWindow.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainWindow.add(backgroundPanel);
backgroundPanel.add(subPanel);
updateGUI();
}
public void updateGUI()
{
mainWindow.setVisible(false);
mainWindow.setVisible(true);
}
public void paintComponent(Graphics g)
{
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
}
Let's break this down....
public class GUI extends JFrame {
JFrame mainWindow = new JFrame();
There is no need to extend from JFrame as you are neither using it nor are you adding any value to the class.
This...
public void paintComponent(Graphics g) {
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
is doing nothing and will never be called, as nothing you've extended from implements a paintComponent method (that is, JFrame does not have a paintComponent methd) (and you class is not attached to anything displayed on the screen anyway). Also, you should NEVER maintain a reference to ANY Graphics context you did not create yourself.
The reason that subPanel is appearing so "small" is because it has not definable size, aside from the border.
You could rectify this in one of three ways...
You could change the layout manager of backgroundPanel to something like BorderLayout
You could override the getPreferredSize method of the subPanel to return a more suitable size or
You could add other components to it and let the layout manager figure it out...
In any case, you should have a look at Laying Out Components Within a Container.
You should also have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting is done in Swing

What causes a "NullPointerException" error here and how can I fix it?

I was trying to make a simple application just to experiment with Java graphics but I got stuck with this error so I would really appreciate if someone could help me with that. :)
I get the following
Exception in thread "main" java.lang.NullPointerException
at Main.draw(Main.java:41)
at Main.createGUI(Main.java:36)
at Main.main(Main.java:20)
Java Result: 1
error when I'm trying to run the following code:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
public JPanel panel;
public static void main(String[] args) {
Main m = new Main();
m.setSize(500, 700);
m.setDefaultCloseOperation(EXIT_ON_CLOSE);
m.createGUI();
m.setVisible(true);
}
private void createGUI() {
Container window = getContentPane();
panel = new JPanel();
panel.setPreferredSize(new Dimension(500, 700));
panel.setBackground(Color.WHITE);
window.add(panel);
Graphics paper = panel.getGraphics();
draw(paper);
}
private void draw(Graphics g){
g.drawRect(100, 100, 100, 100);
}
}
Can someone tell me how can I fix this and what is the cause of the error?
Thank you!
The Graphics object on this line
g.drawRect(100, 100, 100, 100);
is null as you've used JComponent#getGraphics before the UI was visible. This is why it is always better to do custom painting by overriding the paintComponent(Graphics) of the JPanel panel. This will guarantee that the Graphics Object is initialized first before being used.
More on Custom Painting
NEVER, EVER use getGraphics.
As you have found, it can return null. It is, at best, a snap shot of the last paint cycle. Anything you paint to it will be overriden on the next paint cycle.
Painting in Swing is stateless. That is, on each paint cycle, you required to repaint every thing you want painted.
Take a look at Custom Painting for an overview of performing custom painting in Swing
+1 to reimeus
The NullPointerException is caused by Graphics g being null, and you trying to use a null object to call one of Graphics methods.
If you search, you'll see that panel.getGraphics() returning null is a common issue and that there are a few solutions. See: Any alternative to calling getGraphics() which is returning null

JApplet behaving unexpectedly

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.Timer;
public class CountingSheep extends JApplet
{
private Image sheepImage;
private Image backgroundImage;
private GameBoard gameBoard;
private scoreBoard scoreBoard;
public void init()
{
loadImages();
gameBoard = new GameBoard(sheepImage, backgroundImage);
scoreBoard = new scoreBoard();
getContentPane().add(gameBoard);
getContentPane().add(scoreBoard);
}
public void loadImages()
{
sheepImage = getImage(getDocumentBase(), "sheep.png");
backgroundImage = getImage(getDocumentBase(), "bg.jpg");
}
}
The program works correctly when nothing but the GameBoard class is added to the JApplet, however, when I try to add the ScoreBoard class, both Panel classes do not show on the Applet. I'm guessing this is now down to positioning? Any ideas?
EDIT: Gone back to the previously asked question Hovercraft, and found it was due to the layout of the contentPane and the order at with the components were added.
Some suggestions:
Don't draw in the paint method of a JApplet as that is a top-level window and should not be drawn directly on. Instead draw in the paintComponent(Graphics g) method of a JPanel or other JComponent, and then add that JPanel to the JApplet's contentPane.
Similar to his advice about the super call, your first method call in this method should be the super.paintComponent(g); which will refresh the JPanel's graphics.
The flicker is from your drawing directly in the JApplet's paint method. If you do as I suggest, you'll take advantage of Swing's use of double buffering.
Since this is a Swing application, you should avoid using KeyListeners and instead use Key Bindings.
Don't get the Graphics object of a component by calling `getGraphics(). The Graphics object obtained will be short-lived and thus will not persist after any repaint.
The code you've posted above is somewhat confusing to me. What are you trying to do with it? You've added components to the JApplet, and these components should handle their own graphics, and then you're painting on the JApplet as well. What kind of behavior exactly are you trying to achieve?
In your paint method, make sure to call super.paint(g) since it is a method inherited from Container, a superclass of JApplet.
#Override
public void paint(Graphics g)
{
super.paint(g);
...
}

Categories

Resources