EmptyBorders on JPanel in BoxLayout.X_AXIS - java

I have a custom JPanel, which the paintComponent method is overridden to paint an image.
I want to insert several of these custom panels vertically centered in a container. To do this I created a jpanel with BoxLayout.X_AXIS as layout manager.
This works great and shows what I want, but I would like to add margins between the custom panels.
The EmptyMargins are just ignored, and the tricky part is that I can't (or would not like to...) add struts or boxes between them because I need to get each custom panel from a loop which takes all components of the container and cast them into CustomPanel.
See the problem ? If I add struts between the panels there will be a cast exception and EmptyBorders aren't working... Any ideas welcome!
Note : I'm open to other layout manager propositions ! ;-)
Here is the code :
public class StackExemple {
public StackExemple() {
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(600, 300));
JPanel container = new JPanel();
container.setPreferredSize(new Dimension(600, 300));
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
CustomPanel customPanel1 = new CustomPanel();
CustomPanel customPanel2 = new CustomPanel();
CustomPanel customPanel3 = new CustomPanel();
container.add(customPanel1);
container.add(customPanel2);
container.add(customPanel3);
frame.getContentPane().add(container);
frame.pack();
frame.setVisible(true);
//Loop which takes the custompanels
for(Component comp : container.getComponents()) {
CustomPanel panel = (CustomPanel)comp;
//DO SOMETHING
System.out.println("Hello World");
}
}
private class CustomPanel extends JPanel{
private BufferedImage image;
public CustomPanel() {
setPreferredSize(new Dimension(100, 100));
setMinimumSize(getPreferredSize());
setMaximumSize(getPreferredSize());
setBorder(BorderFactory.createEmptyBorder(0,50,0,0));
setBackground(Color.RED);
// try {
// image = ImageIO.read(ClassLoader.getSystemClassLoader().getResource("Ressources/img.png"));
// } catch (IOException ex) {
// System.out.println("Ooops... ");
// }
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// int x = (this.getWidth() - image.getWidth()) / 2;
// int y = (this.getHeight() - image.getHeight()) / 2;
// g.drawImage(image, x, y, null);
}
}
}

Borders are correct, have to getBackground from parent for LineBorders
override Min / Max / PreferredSize for BoxLayout
BoxLayout accepting Min / Max / PreferredSize by default
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class StackExemple {
public StackExemple() {
JFrame frame = new JFrame();
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
CustomPanel customPanel1 = new CustomPanel(Color.blue);
CustomPanel customPanel2 = new CustomPanel(Color.red);
CustomPanel customPanel3 = new CustomPanel(Color.green);
container.add(customPanel1);
container.add(customPanel2);
container.add(customPanel3);
frame.getContentPane().add(container);
frame.pack();
frame.setVisible(true);
for (Component comp : container.getComponents()) {
CustomPanel panel = (CustomPanel) comp;
System.out.println("Hello World");
}
}
private class CustomPanel extends JPanel {
private BufferedImage image;
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 80);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 160);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(400, 320);
}
public CustomPanel(Color c) {
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(10, 10, 10, 10),
BorderFactory.createLineBorder(Color.black, 1)));
//setBorder(BorderFactory.createCompoundBorder(
//BorderFactory.createLineBorder(Color.black, 1),
//BorderFactory.createEmptyBorder(10, 10, 10, 10)));
setBackground(c);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
StackExemple stackExemple = new StackExemple();
}
});
}
}

The underlying reason that the border appears to not be respected is that the panel by default is opaque, that is it guarantees to fill each pixel of its area with a fully solid background color. The area covered by the border is part of the panel's area, so must be filled with the panel's background as well.
As you seem to be doing custom painting anyway, you might consider to report its opaqueness as false and only paint the background (and/or the background image) inside the bordered area:
// in constructor
setOpaque(false);
#Override
protected void paintComponent(Graphics g) {
// take over background filling inside the border
Insets insets = getInsets();
g.setColor(getBackground());
g.fillRect(insets.left, insets.top,
getWidth() - insets.left - insets.right,
getHeight() - insets.top - insets.bottom);
super.paintComponent(g);
// for a background image, you would need to take the insets
// into account as well
// int x = (this.getWidth() - image.getWidth()) / 2;
// int y = (this.getHeight() - image.getHeight()) / 2;
// g.drawImage(image, x, y, null);
}

Related

JPanel and JFrame size not changing [duplicate]

This question already has answers here:
paintComponent not painting onto JPanel
(2 answers)
Closed 5 years ago.
I'm making a game in Java and first I didn't use a JPanel which caused flickering on repaint() and so I decided to use it. I'm not sure how to implement it in my current code. When I tried to do so all I got was a window that was as small as it gets. My original Window class code:
public class Window extends JFrame {
private double stepLen;
public Window(double stepLen) {
this.stepLen = stepLen;
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setTitle("Frogger");
this.setLayout(null);
getContentPane().setBackground(Color.black);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int x = (dim.width - this.getSize().width)/2;
int y = (dim.height - this.getSize().height)/2;
this.setLocation(x, y);
JLabel goal = new JLabel();
goal.setText("|=========|");
goal.setForeground(Color.WHITE);
goal.setFont(new Font("Seif", Font.PLAIN, 20));
add(goal);
goal.setBounds(325, -10, 600, 50);
setFocusable(true);
requestFocusInWindow();
this.setVisible(true);
}
This code works and it creates a window.
Main class:
Window window = new Window(50);
And then I tried to do it this way:
I have separate GameFrame (JFrame) and GameCanvas (JPanel) classes.
The Frame looks like this:
public class GameFrame extends JFrame{
private double stepLen;
public GameFrame() {
this.stepLen = 50;
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setTitle("Frogger");
this.setLayout(null);
this.setVisible(true);
this.getContentPane().setBackground(Color.black);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int x = (dim.width - this.getSize().width)/2;
int y = (dim.height - this.getSize().height)/2;
GameCanvas gcanvas = new GameCanvas();
this.add(gcanvas);
this.pack();
this.setLocation(x, y);
}
}
}
And the GameCanvas class
public class GameCanvas extends JPanel {
public GameCanvas() {
setDoubleBuffered(true);
JLabel goal = new JLabel();
goal.setText("|=========|");
goal.setForeground(Color.WHITE);
goal.setFont(new Font("Seif", Font.PLAIN, 20));
this.add(goal);
goal.setBounds(325, -10, 600, 50);
this.getPreferredSize();
this.setVisible(true);
this.repaint();
}
Camickr is correct - go up vote and mark his answer as correct, this is only here to save him from pulling out what little hair he has remaining
You're using a null layout, without taking over its responsibility
Failed to provide sizing hints to for the component to allow the layout manager (which you're no longer using) to do it's job
This are all common mistakes, to which there are countless answers already provided
GameFrame
public class GameFrame extends JFrame {
private double stepLen;
public GameFrame() {
this.stepLen = 50;
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setTitle("Frogger");
// Well, there's your problem...
//this.setLayout(null);
// Don't do this here...
this.setVisible(true);
this.getContentPane().setBackground(Color.black);
// Simpler way to achieve this
//Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
//int x = (dim.width - this.getSize().width) / 2;
//int y = (dim.height - this.getSize().height) / 2;
GameCanvas gcanvas = new GameCanvas();
this.add(gcanvas);
this.pack();
//this.setLocation(x, y);
setLocationRelativeTo(null);
setVisible(true);
}
}
GameCanvas
public class GameCanvas extends JPanel {
public GameCanvas() {
// Pointless
//setDoubleBuffered(true);
JLabel goal = new JLabel();
goal.setText("|=========|");
goal.setForeground(Color.WHITE);
goal.setFont(new Font("Seif", Font.PLAIN, 20));
this.add(goal);
// Pointless
//goal.setBounds(325, -10, 600, 50);
// Pointless
//this.getPreferredSize();
// Pointless
//this.setVisible(true);
// Pointless
//this.repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
public void paintComponent(Graphics g) {
int firstRoad = 5;
int i = 0;
int max = 10;
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g2);
g2.setColor(Color.WHITE);
g2.drawRect(5, 30, 75, 40);
while (i < max) {
g2.setColor(Color.WHITE);
g2.setStroke(new BasicStroke(3));
if (i % 2 == 0) {
g.setColor(Color.WHITE);
g.drawRect(3, firstRoad + 50 * i, 793, 50);
//g.fillRect(3, firstRoad + 50 * i, 793, 50);
} else {
g2.setColor(Color.WHITE);
g2.drawRect(3, firstRoad + 50 * i, 793, 50);
}
i++;
}
}
}
So, the way I was taught in my AP Computer Science class is to set your frame size and other frame characteristics in your main. Here is an example:
import javax.swing.JFrame;
public class theSetupClass{
public static void main(String[] args){
JFrame theGUI = new JFrame();
theGUI.setSize(300,400); //Sets the frame size to 300 by 400
theGUI.setTitle("Example");
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theComponentClass component = new theComponentClass(); //Create new theComponentClass
frame.add(component);//Add theComponentClass to theGUI
frame.setVisible(true);
}
}
The code above creates the JFrame and adds the following class to it.
import java.awt.*;
import javax.swing.*;
public class theComponentClass extends JComponent{
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Rectangle r = new Rectangle(10,10,this.getWidth()-10,this.getHeight()-10);
//Creates a rectangle that is 10 pixels away from all sides of the frame
g2.fill(r); //Draws and fills the rectangle
}
}
I hope that you find this helpful!

How to add a scrollbar for long JComponents in a JPanel? How to center a JComponent?

Currently, I have to JComponents contained in a JPanel with a vertical box layout.
This way, I can have the first component centered, as shown below, and have the bottom component (which is quite long) below. However, since the bottom component is very long I wanted to add a slider just for that specific component. This way, the user can see all of the bottom component with the upper component remaining centered. However, my code below doesn't fix anything and the scrollbar never even works. The only information about GPComponent and GPinfinity you need to know is they override the preferredSize, minimumSize, maximumSize, and paintComponent methods (they extend JComponent).
JFrame frame = new JFrame();
JPanel panel = new JPanel();
GPComponent gp = new GPComponent(n, k);
GPinfinityComponent gpi = new GPinfinityComponent(n, k);
Box box = new Box(BoxLayout.Y_AXIS);
panel.add(Box.createVerticalGlue());
panel.add(gp);
panel.add(Box.createVerticalGlue());
JScrollPane thePane = new JScrollPane(gpi, JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
panel.add(thePane);
frame.pack();6
frame.add(panel, BorderLayout.CENTER); // just to be clear
frame.setVisible(true);
final int FRAME_WIDTH = 600;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("GP("+n+", "+k+")");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Also: the maximumSize=minimumSize=preferredSize for both components
For the circular one the dimensions are (350, 350) and for the other the dimensions are (5000, 150).
You state:
...and for the other the dimensions are (5000, 150).
If this is the component that is supposed to show the scrollbars, the Java is telling you otherwise, that it is in fact much shorter than you suppose it to be. I wonder if you're setting size instead of preferredSize. You actually should not be setting either but rather should override getPreferredSize() and have it return a dimension appropriate for the component.
For more detailed help, consider creating and posting a minimal example program.
Edit
For example, my MCVE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class PreferredSizeEg extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
public PreferredSizeEg() {
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(new CenterImagePanel());
JScrollPane scrollpane = new JScrollPane(new LongImagePanel(),
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
setLayout(new BorderLayout());
add(centerPanel, BorderLayout.CENTER);
add(scrollpane, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class LongImagePanel extends JPanel {
private static final int LI_PREF_W = 5000;
private static final int LI_PREF_H = 150;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int index = 0;
int spriteWidth = 50;
while ((index) * spriteWidth < getWidth()) {
Color c = index % 2 == 0 ? Color.green : Color.red;
g.setColor(c);
int x = 2 + index * spriteWidth;
int y = 2;
int width = getHeight() - 4;
int height = width;
g.fillOval(x, y, width, height);
index++;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(LI_PREF_W, LI_PREF_H);
}
}
private class CenterImagePanel extends JPanel {
private static final int CIP_PREF_W = 200;
private static final int CIP_PREF_H = CIP_PREF_W;
public CenterImagePanel() {
setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.green);
int x = 5;
int y = x;
int width = getWidth() - 2 * x;
int height = getHeight() - 2 * y;
g.fillOval(x, y, width, height);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(CIP_PREF_W, CIP_PREF_H);
}
}
private static void createAndShowGui() {
PreferredSizeEg mainPanel = new PreferredSizeEg();
JFrame frame = new JFrame("PreferredSizeEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:

Creating Vertical Scrollable Pane for JPanels

I am trying to make a JScrollPane that contains JPanels that have charts from the JFreeChart API. GenerateChartPanel is a method that return the charts in a JPanel so I can quickly make a bunch of them. So far I have this in main:
public static void main (String[] args){
JFrame main = new JFrame();
main.setLayout(new BorderLayout());
main.setPreferredSize(new Dimension(500,500));
//Creates specFrame
JScrollPane specScrollPane = new JScrollPane();
JPanel container = new JPanel();
container.setLayout(new GridLayout());
container.add(generateSpecPanelFromSmiles("C"));
container.add(generateSpecPanelFromSmiles("CC"));
container.add(generateSpecPanelFromSmiles("CCC"));
container.setVisible(true);
specScrollPane.setVisible(true);
specScrollPane.add(container);
main.add(specScrollPane);
RefineryUtilities.centerFrameOnScreen(main);
main.setVisible(true);
When I run this, nothing shows up. Apparently you can't pack, setCloseOp, setLayout, or center these panes so I commented them out. What am I missing?
EDIT: Getting Dimensions
specPanel.addComponentListener(new java.awt.event.ComponentAdapter() {
#Override
public void componentResized(ComponentEvent event) {
specPanel.setSize(Math.min(specPanel.getPreferredSize().width, specPanel.getWidth()),
Math.min(specPanel.getPreferredSize().height, specPanel.getHeight()));
}
});
thanks
JScrollPane is designated to nest only one JComponent
you have to put another JPanel to JScrollPane, to this JPanel you can to add your three components
have to change default Layout Manager (FlowLayout) for parent JPanel (contains three components), which one to depends of those components, how they returns its PreferredSize, maybe to start with GridLayout(all childs has the same size on the screen)
EDIT
whatever the generateSpecPanelFromSmiles is it, to must returns PreferredSize to parentPanel, e.g. (playing with PreferredSize with GridLayout and BoxLayout - box accepting min, max and preferred size)
.
.
.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class JPanelsInsideJScrollPane {
private JFrame frame = new JFrame("JPanels Inside JScrollPane");
private JScrollPane scrollPane = new JScrollPane();
private JPanel parentPanel, childOne, childTwo, childThree;
private JButton button = new JButton("Change, Switch Layout Manager to BoxLayout");
public JPanelsInsideJScrollPane() {
parentPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(new Dimension(800, 600));
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
parentPanel.setLayout(new GridLayout(0, 1));
childOne = new JPanel() {
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(500, 300);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
childTwo = new JPanel() {
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(600, 400);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
childThree = new JPanel() {
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(800, 600);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
};
parentPanel.add(childOne);
parentPanel.add(childTwo);
parentPanel.add(childThree);
scrollPane.setViewportView(parentPanel);
scrollPane.getVerticalScrollBar().setUnitIncrement(30);
scrollPane.getHorizontalScrollBar().setUnitIncrement(30);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
LayoutManager manager = parentPanel.getLayout();
if ((manager != null) && (manager instanceof BoxLayout)) {
parentPanel.setLayout(new GridLayout(0, 1));
button.setText("Change, Switch Layout Manager to BoxLayout");
} else if ((manager != null) && (manager instanceof GridLayout)) {
parentPanel.setLayout(new BoxLayout(parentPanel, BoxLayout.PAGE_AXIS));
button.setText("Change, Switch Layout Manager to GridLayout");
}
parentPanel.revalidate();
parentPanel.repaint();
}
});
frame.add(scrollPane);
frame.add(button, BorderLayout.SOUTH);
frame.setSize(400, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JPanelsInsideJScrollPane();
}
});
}
}

Initialization in paintComponent doesn't work

I'm doing some exercise to understand Java and Swing API. Why do I have a nullPointerException in the Disegno constructor? I want to print the coordinates of the two rectangles, but they seem not to be initialitied.
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Disegno extends JFrame{
Disegno(){
this.setSize(500, 500);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
MyPanel aba = new MyPanel();
this.setContentPane(aba);
this.setVisible(true);
System.out.println(aba.rect.blue.x + "-" + aba.rect.blue.y);
System.out.println(aba.rect.yellow.x + "-" + aba.rect.yellow.y);
}
public static void main(String[] args){
new Disegno();
}
}
class MyPanel extends JPanel{
JPanel up, down;
RectArea rect;
MyPanel(){
this.setLayout(new BorderLayout());
up = new JPanel();
this.add(up, BorderLayout.NORTH);
up.setBackground(Color.red);
up.setVisible(true);
down = new JPanel();
down.setBackground(Color.green);
this.add(down, BorderLayout.SOUTH);
down.setVisible(true);
rect = new RectArea();
this.add(rect, BorderLayout.CENTER);
this.setVisible(true);
}
}
class RectArea extends JPanel{
Rectangle blue, yellow;
boolean check = false;
RectArea(){
super();
this.setVisible(true);
}
public void initRect(){
blue = new Rectangle(0, 0, 100, 100);
yellow = new Rectangle(this.getWidth(), this.getHeight(), 100, 100);
System.out.println("ok");
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(check == false){
this.initRect();
check = true;
}
System.out.println(this.getWidth() + "-" + this.getHeight());
g.setColor(Color.blue);
g.fillRect(blue.x, blue.y, blue.width, blue.height);
g.setColor(Color.yellow);
g.fillRect(yellow.x - yellow.width, yellow.y - yellow.height, yellow.width, yellow.height);
}
}
Others have helpfully suggested ways to detect and avoid the NullPointerException. Unfortunately, you can't rely on when your implementation of paintComponent() will be called. Instead,
Determine the required geometry as a function of the current widow's size; resize the window in the example below to see how yellow seems to stick to the bottom right corner.
Because MyPanel contains no components of its own, you should override getPreferredSize(), as #nIcE cOw shows here.
Use pack() to size the enclosing Window.
Build on the event dispatch thread.
Addendum: I can't understand why you override the method getPreferredSize().
Subclasses of JComponent override getPreferredSize() so that pack() can size the Window "to fit the preferred size and layouts of its subcomponents." That way you don't have to worry if the user has a different font, for example. MyPanel just draws geometric shapes, so you're the boss on preferred size. As discussed here, a demo may use setPreferredSize() for convenience, but you should understand the limitations of doing so.
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/q/11376272/230513
*/
public class Disegno extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Disegno();
}
});
}
Disegno() {
this.setSize(500, 500);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
MyPanel aba = new MyPanel();
this.add(aba);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
class MyPanel extends JPanel {
private JPanel up, down;
private RectArea rect;
MyPanel() {
super(new BorderLayout());
up = new JPanel();
up.setBackground(Color.red);
this.add(up, BorderLayout.NORTH);
rect = new RectArea();
this.add(rect, BorderLayout.CENTER);
down = new JPanel();
down.setBackground(Color.green);
this.add(down, BorderLayout.SOUTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}
class RectArea extends JPanel {
private Rectangle blue = new Rectangle(0, 0, 100, 100);
private Rectangle yellow = new Rectangle(0, 0, 100, 100);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println(this.getWidth() + " x " + this.getHeight());
g.setColor(Color.blue);
g.fillRect(blue.x, blue.y, blue.width, blue.height);
g.setColor(Color.yellow);
int dx = getWidth() - yellow.width;
int dy = getHeight() - yellow.height;
g.fillRect(dx, dy, yellow.width, yellow.height);
}
}
}
You never called rect.initRect(); anywhere, that's why you getting error related to NullPointerException at those System.out.println() lines. Why you using panelObject.setVisible(true) inside each class, first add them to the JPanel and simply call setVisible(...) on the JFrame that will do. Here watch your modified code with the said thingies, working as expected :
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Disegno extends JFrame{
Disegno(){
this.setSize(500, 500);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
MyPanel aba = new MyPanel();
this.setContentPane(aba);
this.setVisible(true);
System.out.println(aba.rect.blue.x + "-" + aba.rect.blue.y);
System.out.println(aba.rect.yellow.x + "-" + aba.rect.yellow.y);
}
public static void main(String[] args){
new Disegno();
}
}
class MyPanel extends JPanel{
JPanel up, down;
RectArea rect;
MyPanel(){
this.setLayout(new BorderLayout());
up = new JPanel();
this.add(up, BorderLayout.NORTH);
up.setOpaque(true);
up.setBackground(Color.red);
down = new JPanel();
down.setOpaque(true);
down.setBackground(Color.green);
this.add(down, BorderLayout.SOUTH);
rect = new RectArea();
rect.initRect();
this.add(rect, BorderLayout.CENTER);
}
}
class RectArea extends JPanel{
Rectangle blue, yellow;
boolean check = false;
RectArea(){
super();
setOpaque(true);
}
public void initRect(){
blue = new Rectangle(0, 0, 100, 100);
yellow = new Rectangle(this.getWidth(), this.getHeight(), 100, 100);
System.out.println("ok");
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(check == false){
this.initRect();
check = true;
}
System.out.println(this.getWidth() + "-" + this.getHeight());
g.setColor(Color.blue);
g.fillRect(blue.x, blue.y, blue.width, blue.height);
g.setColor(Color.yellow);
g.fillRect(yellow.x - yellow.width, yellow.y - yellow.height, yellow.width, yellow.height);
}
}
If you would write a System.out.println() inside the intiRect() you will know, the lines which are giving you errors are being called before the paintComponent(...) method itself. So it appears to me, that you have to take that logic out of the paintComponent(...) method and keep it somewhere else, or else remove those lines, if you don't need them.
You are trying to access aba.rect.blue and aba.rect.yellow in your Disegno constructor, however these are not initialized until RectArea.paintComponent is called, so it throws an NPE.
Are you sure that your code gave a NullPointerException .......??
Because when i ran your code, it worked fine...
Output:
ok
484-442

Drawing rectangles on a JPanel

I have a JScrollPane and on top of it I have a JPanel named 'panel1'.
I want some rectangles to be drawn on this JPanel.
I have a class named DrawRectPanel which extends JPanel and does all the drawing stuff.
The problem is that, I tried to draw the rectangles on panel1 by writing the following code :
panel1.add(new DrawRectPanel());
but nothing appeared on panel1
then I tried, just as a test to the class DrawRectPanel :
JFrame frame = new JFrame();
frame.setSize(1000, 500);
Container contentPane = frame.getContentPane();
contentPane.add(new DrawRectPanel());
frame.show();
This worked, and produced the drawings but on a separate JFrame
How can I draw the rectangles on panel1 ?
Thanks in advance.
EDIT :
code for DrawRectPanel
public class DrawRectPanel extends JPanel {
DrawRectPanel() {
Dimension g = new Dimension(400,400);
this.setPreferredSize(g);
System.out.println("label 1");
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("label 2");
g.setColor(Color.red);
g.fillRect(20, 10, 80, 30);
}
}
only label 1 is printed on the screen
still no idea,
for example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class CustomComponent extends JFrame {
private static final long serialVersionUID = 1L;
public CustomComponent() {
setTitle("Custom Component Graphics2D");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void display() {
add(new CustomComponents());
pack();
// enforces the minimum size of both frame and component
setMinimumSize(getSize());
setVisible(true);
}
public static void main(String[] args) {
CustomComponent main = new CustomComponent();
main.display();
}
}
class CustomComponents extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}
instead of adding
contentPane.add(new DrawRectPanel());
you should do
contentPane.add(panel1);
Because you already have new DrawRectPanel in panel1. But in your code you are adding another instance of DrawRectPanel in contentPane. And never added panel1 in none of your container.
to fix your problem, change "paintComponent" to "paint" when the window repaints automatically, it should work.

Categories

Resources