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)
Related
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();
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.
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());
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.
I have a JPanel using GridLayout which contains 6 JLabels. If i add only this JPanel to a JFrame everything works fine, but when I add it on BorderLayout.WEST (along with 3 other panels on EAST, CENTER and SOUTH) it just won't show up.
Here's the code I'm using:
public class SwingView extends JFrame {
private DeckLabel[] terrains={
new DeckLabel(new ImageIcon("assets/graphics/mountains.png"),0),
new DeckLabel(new ImageIcon("assets/graphics/planes.png"),1),
new DeckLabel(new ImageIcon("assets/graphics/forest.png"),2),
new DeckLabel(new ImageIcon("assets/graphics/fields.png"),3),
new DeckLabel(new ImageIcon("assets/graphics/swamp.png"),4),
new DeckLabel(new ImageIcon("assets/graphics/desert.png"),5)};
public SwingView() {
super("Frame");
this.setSize(680, 740);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
Utilities.center(this);
// panels
//terrains
JPanel terrainsPanel = new JPanel();
terrainsPanel.setSize(100, 640);
terrainsPanel.setLayout(new GridLayout(6, 1));
//map
JPanel mapPanel = new JPanel();
mapPanel.setSize(480, 640);
//info
JPanel infoPanel = new JPanel();
infoPanel.setSize(100, 640);
//chat
JPanel chatPanel = new JPanel();
chatPanel.setSize(680, 100);
chatView.setEditable(false);
txtChat.addKeyListener(this);
chatPanel.add(txtChat, BorderLayout.SOUTH);
chatPanel.add(chatView);
// terrains
for (int i = 0; i < 6; i++) {
terrainsPanel.add(terrains[i]);
}
this.add(mapPanel,BorderLayout.CENTER);
this.add(terrainsPanel, BorderLayout.WEST);
this.add(infoPanel, BorderLayout.EAST);
this.add(chatPanel, BorderLayout.SOUTH);
}
}
public class DeckLabel extends JLabel{
private Image image;
private int index;
public DeckLabel(ImageIcon icon,int index){
this.image=icon.getImage();
this.index=index;
}
#Override
public void paint(Graphics g){
BufferedImage bi = new BufferedImage(85, 78,
BufferedImage.TYPE_INT_RGB);
Graphics2D tg = bi.createGraphics();
tg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// draw basic tile
tg.drawImage(image, 0, 0, null);
g.drawImage(bi,0,0,null);
}
}
Thank you
plenty issues
use JPanel instead of JLabel,
override paintComponent instead of paint for JLabel/JPanel/Swing JComponents
1st. code line should be super.pain(Component), or for JPanel to stop repainting (mouse and key events)
or to use JLabel.setIcon for Image
something wrong came from Utilities.center(this);, did you tried to layout container
FlowLayout is default LayoutManager for JPanel, then chatPanel.add(txtChat, BorderLayout.SOUTH); is ignored without missing code line chatPanel.setLayout(new BorderLayout)
txtChat.addKeyListener(this); I'm hope that isn't some of JTextComponents, if yes then to use DocumentListener/Filter instead
As your DeckLabel class sets no text for the JLabel, the component has no minimum and preferred size. So the border layout will assume a size of 0 -> component not visible. The same happens when you use a JPanel.
Call setPreferredSize(), setMinimumSize() or override getMinimumSize()/getPreferredSize().