Why isn't a painting drawn to the screen? - java

I have this simple code which is supposed to have three panels and draws and oval at the top left corner of each panel
public class main1 extends JPanel {
public main1() {
// TODO Auto-generated constructor stub
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JPanel1 panel1 = new JPanel1(Color.YELLOW);
panel1.setBackground(Color.black);
JPanel1 panel2 = new JPanel1(Color.red);
panel2.setBackground(Color.blue);
JPanel1 panel3 = new JPanel1(Color.pink);
panel3.setBackground(Color.green);
this.add(panel1);
this.add(panel2);
this.add(panel3);
}
class JPanel1 extends JPanel{
Color c;
public JPanel1(Color c) {
this.c = c;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println(this.getBounds().x);
g.setColor(c);
g.drawOval(this.getBounds().x, this.getBounds().y, 200, 200);
}
}
public static void main(String args[]) {
JFrame f = new JFrame("Two Panels");
f.setContentPane(new main1());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setVisible(true);
}
}
however, it only seems to draw the first oval of the first panel and ignores the rest.
can somebody explain. What am I doing wrong?

Do not use getBounds() as it gives the component location relative to its parent. Use panel's coordinates and its width and height instead. In your example you are painting outside the boundaries of the panels. For example use this to draw an oval:
g.drawOval(0, 0, getWidth(), getHeight());
Some side notes:
Do not call setSize(), override panel's getPreferredSize() and pack() the frame. For example:
public Dimension getPreferredSize(){return new Dimension(400, 400);}
Then, add frame.pack(); before making the frame visible.
See Java Naming Conventions.
See Performing Custom Painting and Painting in AWT and Swing for more information.

Related

JPanel not calling paintComponent in java

I have worked on this for hours upon hours and it doesn't work.
I want to have a pixel appear on the screen, but the paint component doesn't work I don't understand why.
The setupFrame method is called from the main method.
public static void setupFrame()
{
JFrame frame = new JFrame("graphicsTest");
JPanel panel = new JPanel();
panel.setBounds(0, 0, 1080, 1080/2);
frame.add(panel);
frame.pack();
frame.setSize(1080, 1080/2);
frame.setVisible(true);
frame.setResizable(false);
frame.repaint();
}
#Override
public void paintComponent(Graphics g) {
g.fillRect(0, 0, 50, 50);
}
You're overloading the paintComponent() in the class you've created (let's call it MyPanel) but you're creating an instance of another class:
JPanel panel = new JPanel();
So there's no instance of MyPanel here and the method is not called. You need to use the class where you've overloaded the paintComponent method:
MyPanel panel = new MyPanel();
Or (this should be equivalent):
JPanel panel = new MyPanel();

JButton responds in JFrame, but not in a JPanel

I'm new to java and I'm trying to figure out how action listeners and buttons work. I've found that I can get a working JButton if I put it directly into my JFrame object. But if I put it in a JPanel within that JFrame, it won't respond. Why is that?
Main.java
public class Main {
private static Frame f = new Frame();
public static void main(String[] args) {}
}
Frame.java
public class Frame extends JFrame {
private final int WIDTH = 640, HEIGHT = 480;
private Panel p = new Panel();
Frame() {
super("Java Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(WIDTH, HEIGHT);
this.setLayout(null);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
p.paintComponent(g);
}
}
Panel.java
public class Panel extends JPanel {
JButton b = new JButton("Button");
Panel() {
b.setBounds(0, 0, 200, 100);
add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.setText("Pressed");
}
});
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
b.paint(g);
}
}
I am not a Swing expert so I can't really explain why it does not work. It seems like an unresponsive button is painted on top of you button. I tweaked it a little and here are a few modifications to get it to work:
Add the panel to the Frame: add(p);
Remove the this.setLayout(null); line, it seems to mess up the frame
To set the size of the Frame, use setPreferredSize: this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
You also need to call pack() at then end of your Frame constructor.
And you need to remove b.paint(g) from your Panel.paintComponent(), this seems to be what paints the "unresponsive" button, (see image at the end of the answer).
Optionally, you can remove the paint() from the Frame, it does nothing more than the JFrame's one
Here is a modified working version:
class Frame extends JFrame {
private final int WIDTH = 640, HEIGHT = 480;
private Panel p = new Panel();
Frame() {
super("Java Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
this.setLocationRelativeTo(null);
this.setVisible(true);
// add the panel to the frame
add(p);
pack();
}
}
class Panel extends JPanel {
JButton b = new JButton("Button");
Panel() {
b.setBounds(0, 0, 200, 100);
add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.setText("Pressed");
}
});
}
// You can also get rid of this method,
// I just leave it here to show that I removed the b.paint(g) line
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
}
Here is what the same code shows if you leave b.paint(g) in Panel.paintComponent(), as you can see there are 2 buttons, the one in the corner does not work.

Painting two squares with JPanel.paintComponent() - wrong size

I am trying to paint two squares of defined size, one located next to another in a row, using paintComponent() method of JPanel.
Here what I tried so far:
1. BorderLayout
I tried to draw each square in a separate subclass of JPanel, and then add these JPanels to a JFrame.
Result: squares are squashed to the opposite sides of JPanel: height is as expected but width is minimal.
JFrame frame = new JFrame();
GreenPanel greenPanel = new GreenPanel();
frame.getContentPane().add(BorderLayout.WEST, greenPanel);
BluePanel bluePanel = new BluePanel();
frame.getContentPane().add(BorderLayout.EAST, bluePanel);
frame.setSize(500, 350);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
class GreenPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(0, 0, 100, 100);
}
}
class BluePanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
}
2. FlowLayout
I tried to add my "children" JPanels with painted squares to a "parent" JPane and then call JFrame.setContentPane(JPanel).
Result: squares are painted in top-center region as tiny squares.
JFrame frame = new JFrame();
JPanel outerPanel = new JPanel();
frame.setContentPane(outerPanel);
GreenPanel greenPanel = new GreenPanel();
outerPanel.add(greenPanel);
BluePanel bluePanel = new BluePanel();
outerPanel.add(bluePanel);
frame.setSize(500, 350);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
class GreenPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(0, 0, 100, 100);
}
}
class BluePanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
}
What am I doing wrong? Is there any way I can force layout managers to respect the size of the squares painted with paintComponent() ?
Make the following changes. See comments for explanations.
JFrame frame = new JFrame();
//add layout manager. You can achieve the desired layout
//with GridLayout, Box layout and others
frame.getContentPane().setLayout(new GridLayout(1,2));
GreenPanel greenPanel = new GreenPanel();
//set preferred size to the panel
greenPanel.setPreferredSize(new Dimension(100,100));
frame.add(greenPanel);
BluePanel bluePanel = new BluePanel();
//set preferred size to the panel
bluePanel.setPreferredSize(new Dimension(100,100));
frame.getContentPane().add(bluePanel);
//let the frame adapt to the panels size
//frame.setSize(500, 350);
frame.validate();
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Don't hesitate to ask for clarifications as needed.
(BTW overriding paintComponent(Graphics g) is not really needed. You could simply set preferred size and color to each JPanel)

Java - Graphics being erased after returning from method

public void graph()
{
// Build the panel
JFrame graphWindow = new JFrame();
JPanel graphPanel = new JPanel();
Graphics g;
graphWindow.setTitle(inputField.getText());
graphWindow.getContentPane().add(graphPanel,"Center");
graphPanel.setBackground(Color.white);
graphWindow.setSize(600, 600);
graphWindow.setLocation(200,300);
graphWindow.setVisible(true);
g = graphPanel.getGraphics();
graphPanel.addMouseListener(this);
g.setFont(new Font("Times Roman", Font.BOLD, 20));
g.drawString("Test",100,100);
}
My issue is that when my program returns from the method, the drawing is erased and I'm left with a blank white window. If I capture the method in a while loop, it isn't erased. Is there some way to preserve the graphics after returning from the method?
Make a JFrame. Make it visible. Put a JPanel in it. Override paintComponent in the JPanel to draw whatever you are trying to draw.
For instance:
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
// drawing code using g
}
};
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setSize(600, 600);
frame.setLocation(200,300);
frame.setVisible(true);
As soon as the JPanel calls it's paintComponent method, it will replace your drawing with the default look of a panel. Instead, create your JPanel with a custom paintComponent method (you can do it as an anonymous class like the example below or create your own class extending from JPanel).
// Build the panel
JFrame graphWindow = new JFrame();
JPanel graphPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(new Font("Times Roman", Font.BOLD, 20));
g.drawString("Test", 100, 100);
}
};
graphWindow.setTitle("Blabla");
graphWindow.getContentPane().add(graphPanel, "Center");
graphPanel.setBackground(Color.white);
graphPanel.setOpaque(true); // make the JPanel opaque
graphWindow.setSize(600, 600);
graphWindow.setLocation(200, 300);
graphWindow.setVisible(true);
Also, I noticed that you want a white background. You have to make your JPanel opaque, to do so. I inserted a line in your code to do that.

Panel added to BorderLayout.CENTER does not occupy remaining space

I am currently learning to program GUI in Java, and I have a problem where the CENTER component does not occupy the remaining space in the frame. From what I've read BorderLayout will grant components in north/south their preferred height and the stretch it out to the edges, and west/east will be the opposite. The center component will then get whatever space is left. What I am trying to do is to create a simple window with a panel in the north region, and a panel in the center region. I give each their own background color so I can easily see the space they are given. However, instead of getting a window with a yellow top bar and the remaining space being occupied by the magenta panel, I get this.
The top panel is just a regular JPanel, but the center panel is a class extending JPanel which overrides paintComponent and fills the panel with a color. If I hardcode in a bigger area in the fillRect() it will actually fill the window. So I suspect there's something wrong happening when I call getHeight() and getWidth in the method. It also might be worth mentioning that the dawPanel always will paint a perfect square, if I resize the window into a rectangle longer on the Y-aksis the gap will appear on the bottom instead.
So my question is, how can I get the component added to the Borderlayout.CENTER to occupy all remaining space in the frame.contentPane()?
package oblig1;
import java.awt.*;
import javax.swing.*;
public class Oblig1
{
JFrame frame;
JPanel infoPanel;
DrawingPanel drawPanel;
public static void main(String[] args)
{
Oblig1 game = new Oblig1();
}
public Oblig1()
{
frame = new JFrame("Parachute Game");
frame.setSize(860, 640);
infoPanel = new JPanel();
drawPanel = new DrawingPanel();
infoPanel.setBackground(Color.yellow);
infoPanel.setPreferredSize(new Dimension(840, 20));
infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));
drawPanel.setPreferredSize(new Dimension(840, 620));
frame.getContentPane().add(infoPanel, BorderLayout.NORTH);
frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setResizable(false);
frame.setVisible(true);
}
//This class represents the panel that paints all animated parts of the game
public class DrawingPanel extends JPanel
{
public DrawingPanel()
{
setDoubleBuffered(true);
}
#Override
protected void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.MAGENTA);
g2d.fillRect(0, 0, drawPanel.getHeight(), drawPanel.getWidth());
}
}
}
issue came from two code lines (and one code line missed
infoPanel.setPreferredSize(new Dimension(840, 20));
and
infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));
BoxLayout required Min, Max and PreferredSize, otherwise missed Dimensions collided with another PreferredSize, in this case (infoPanel.setPreferredSize(new Dimension(840, 20)); ) that is laid in JFrame that uses BorderLayout
remove infoPanel.setPreferredSize(new Dimension(840, 20));, or its widht must be less than PreferredSize used for JPanel
painting in Swing by default never returns PreferredSize correctly back to the container, you jave to override getPreferredSize, for BoxLayout min, max and preferred size
use JFrame.pack() instead of sizing for min,max and preferredSize directly to the JComponents or container, nor to setSize for JFrame
not true at all, to see my EDIT --> use another LayoutManager for JPanel to reduce funny issue with painting if is JFrame resized
your paintComponent missed important code line super.paintComponent(g);
e.g.
import java.awt.*;
import javax.swing.*;
public class Oblig1 {
JFrame frame;
JPanel infoPanel;
DrawingPanel drawPanel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Oblig1();
}
});
}
public Oblig1() {
frame = new JFrame("Parachute Game");
//frame.setSize(860, 640);
infoPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
};
drawPanel = new DrawingPanel();
infoPanel.setBackground(Color.yellow);
//drawPanel.setPreferredSize(new Dimension(840, 20));
infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));
//drawPanel.setPreferredSize(new Dimension(840, 620));
frame.getContentPane().add(infoPanel, BorderLayout.NORTH);
frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
//This class represents the panel that paints all animated parts of the game
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
setDoubleBuffered(true);
}
#Override
public Dimension getMinimumSize() {
return new Dimension(300, 300);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.MAGENTA);
//g2d.fillRect(0, 0, getHeight(), getWidth());
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
}
EDIT
to my point, is simple wrong
use another LayoutManager for JPanel to reduce funny issue with painting if is JFrame resized
there are wrong, reversed parameters for Height and Width, wrong code line g2d.fillRect(0, 0, getHeight(), getWidth()); should be g2d.fillRect(0, 0, getWidth(), getHeight());

Categories