I set a JPanel as a contentPane of my JFrame.
When I use:
jPanel.setBackground(Color.WHITE);
The white color is not applied.
But when I use:
jFrame.setBackground(Color.WHITE);
It works... I am surprised by this behaviour. It should be the opposite, shouldn't it?
SSCCE:
Here is an SSCCE:
Main Class:
public class Main {
public static void main(String[] args) {
Window win = new Window();
}
}
Window Class:
import java.awt.Color;
import javax.swing.JFrame;
public class Window extends JFrame {
private Container mainContainer = new Container();
public Window(){
super();
this.setTitle("My Paint");
this.setSize(720, 576);
this.setLocationRelativeTo(null);
this.setResizable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainContainer.setBackground(Color.WHITE); //Doesn't work whereas this.setBackground(Color.WHITE) works
this.setContentPane(mainContainer);
this.setVisible(true);
}
}
Container Class:
import java.awt.Graphics;
import javax.swing.JPanel;
public class Container extends JPanel {
public Container() {
super();
}
public void paintComponent(Graphics g) {
}
}
The reason is very simple include the following line
super.paintComponent(g);
when you override paintComponent.
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
Now it works perfectly.
You should always do this unless you have a very specific reason to do so .
[PS:Change the colour to red or something darker to notice the difference as sometimes it becomes difficult to differentiate between JFrame's default grey colour and White colour]
With my testcode it works the way you expected it to work:
public class Main {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(new Dimension(400,400));
f.setLocationRelativeTo(null);
JPanel p = new JPanel();
p.setSize(new Dimension(20,20));
p.setLocation(20, 20);
//comment these lines out as you wish. none, both, one or the other
p.setBackground(Color.WHITE);
f.setBackground(Color.BLUE);
f.setContentPane(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Related
To provide some background info that might help, I am creating the game pong and I decided to add an escape/pause menu (when you press escape on the keyboard a menu pops up with some settings), I looked around and found that the best way to do this is to use JLayeredPane and add another JPanel on top. However, when I added my 'painter' class to the JLayeredPane, the paint(Graphics g) method stopped getting called (it worked fine when I just added it to the JFrame).
import javax.swing.*;
public class Game extends JFrame {
public static Painter painter;
public Game() {
setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane lp = getLayeredPane();
painter = new Painter();
add(lp);
}
public static void main(String[] args) {
Game frame = new Game();
frame.setVisible(true);
painter.repaint();
}
}
And here is my Painter class
import java.awt.*;
import javax.swing.*;
public class Painter extends JPanel {
public void paint(Graphics g) {
System.out.println("Working");
super.paint(g);
}
}
Instead of add(lp);, I originally tried lp.add(painter); in which case the paint method never got called. By doing add(lp) I get an IllegalArgumentException for adding container's parent to itself.
Here is mcve of using LayeredPane :
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class Game extends JFrame {
public Game() {
setSize(250, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane lp = getLayeredPane();
//assign layout manager. otherwise you need to set content
//bounds (not recommended)
lp.setLayout(new BorderLayout());
Painter painter = new Painter();
lp.add(painter,1);
}
public static void main(String[] args) {
Game frame = new Game();
frame.setVisible(true);;
}
}
class Painter extends JPanel {
#Override
protected void paintComponent(Graphics g) { //do not override paint
super.paintComponent(g);
g.drawString("Working",50,50);
}
}
I'm using paintComponent to make a GUI for a class assignment and it's just not affecting the appearance of the GUI at all. To start, I'm just setting the background to white. The following code works:
import javax.swing.*;
import java.awt.*;
public class PA05a extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame("MouseDrawDemo");
JPanel content = new JPanel();
content.setBackground(Color.WHITE);
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
}
but this does not:
import javax.swing.*;
import java.awt.*;
public class PA05a extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame("MouseDrawDemo");
JPanel content = new JPanel();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
//add backdrop
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
}
}
I can't just not use paintComponent because I'll later be adding things that will change from frame to frame. Can someone pinpoint where I'm missing something?
JPanel content = new PA05a();
You did not create an object of PA05a. ;)
You just forgot to create your object. Change your code to:
import javax.swing.*;
import java.awt.*;
public class PA05a extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame("MouseDrawDemo");
JPanel content = new PA05a();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
//add backdrop
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
}
}
Im trying to add a JScrollpane to my JPanel. The problem is that the scrollpane doesn't recognize that my drawing is outside the frame. So how do I add the JScrollpane correctly?
Main class:
public MainFrame() extends JFrame{
public MainFrame() {
Container container = getContentPane();
container(new BorderLayout());
container.add(new JScrollPane(new Drawing()));
setSize(1280,720);
setVisible(true);
}
Drawing class:
public class Drawing() extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawLine(10, 100, 30000, 10);
}
}
There are a couple of errors in your code, let's step through each of them:
You're extending JFrame, and you should avoid it, see: Extends JFrame vs. creating it inside the program for more information about it. You're actually not changing its behavior so it's not needed to extend it.
For your JScrollPane to show the whole line, you need to change your window's size to be the same size of your line (as shown in this answer by #MadProgrammer).
Related to point 2, avoid the use of setSize(...) and instead override getPreferredSize(): See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more information
You forgot to call super.paintComponent(...) method in your paintComponent() method.
Related to points 2, 3, you need to call pack() so Swing calculates the best preferred size for your component.
See this example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LongDraw {
private JFrame frame;
private Drawing drawing;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LongDraw()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
drawing = new Drawing();
JScrollPane scroll = new JScrollPane(drawing);
frame.add(scroll);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Drawing extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(10, 100, 3000, 10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3000, 500);
}
}
}
Which produces something similar to this:
I am learning Java and I have started to play with drawing possibilities.
Basically I have 2 questions:
Why do I have to override paintCompoment method in order to paint something on JPanel?
Taking into account the first example when I call f.add(new MyPanel()); it creates a new MyPanel object and draw the text. How come the text is drawn? Method paintComponent(g) is not called.
To me it looks like I have two options:
First one (from http://docs.oracle.com/javase/tutorial/uiswing/painting/step2.html):
package painting;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class SwingPaintDemo2 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
}
class MyPanel extends JPanel {
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
}
public Dimension getPreferredSize() {
return new Dimension(250,200);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw Text
g.drawString("This is my custom Panel!",10,20);
}
}
Second one: which works as well
Graphics g = panel.getGraphics();
g.setColor(new Color(255, 0, 0));
g.drawString("Hello", 200, 200);
g.draw3DRect(10, 20, 50, 15, true);
panel.paintComponents(g);
You are not supposed to call paintComponent() yourself.
The paintComponent() is called automatically (by the UI thread).
If you leave the paintComponent() method empty, it will be invoked but nothing will be painted because it is empty.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyDrawPanel extends JPanel{
public void paintComponents(Graphics g){
g.setColor(Color.orange);
g.fillRect(20,50,100,100);
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.getContentPane().add(paintComponents(g));
frame.setVisible(true);
}
}
I think I should add something arguments in frame.getContentPane().add(paintComponents(g));.
I looked up Graphics class but I'm still struggling with it. What should be the parameter of it?
try this
public class MyDrawPanel extends JPanel{
MyDrawPanel()
{
setOpaque(true);
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.orange);
g.fillRect(20,50,100,100);
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyDrawPanel());
frame.setBounds(10,10,500, 500);
frame.setVisible(true);
}
}
I'm no awt expert, but what I think you want to do is add a Canvas object to your content pane from the JFrame, then paint a Graphics object on it.
Okay, this is what I came up with:
public class MyDrawPanel extends JPanel
{
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
MyDrawPanel panel = new MyDrawPanel();
panel.setOpaque(true);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.orange);
g.fillRect(20,50,100,100);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
createAndShowGUI();
}
});
}
}
Notes:
There are several problems with your line frame.getContentPane().add(paintComponents(g));. What you said is "add to the content pane the result of calling paintComponents on g. Where did g come from? You can not used a variable until declared. The result of calling paintComponents is void which means the result cannot be used as an argument to a method. Presumably you had compiler errors.
I changed paintComponents to paintComponent. The former is used to control painting of subcomponents and in general should not be overridden.
Swing objects should not be created on the main thread. The details are complicated for a beginner (and described here in detail). Mostly you can just memorize the SwingUtilities.invokeLater pattern used above.