I want to draw lines and more on a JPanel, add that to a JFrame and using .pack() afterwards. My problem is that I dont get how to use a Layout Manager in that particular case. Usually I add a button or something to the panel by using a gridBagLayout and I totally understand that. But with graphics 2D I kind of just draw directly to the panel. Therfore I cant use .pack() properly. Does somebody know how to pack() that jPanel the right way? My code looks like that:
public class NetworkViewPanel extends JPanel implements KeyListener, ActionListener {
public NetworkViewPanel(NetworkAI network) {
this.network = network;
this.netList = network.getLayerList();
addKeyListener(this);
setFocusable(true);
this.setLayout(new GridLayout(2, 2, 2, 2)); // does that even make sense ?
}
public void paint(Graphics g) {
super.paint(g);
g2 = (Graphics2D) g;
if (showStandardView) {
drawRectangles();
drawLines();
} else {
drawRectangles();
drawLinesSpecial(listIndex, xIndex);
}
}
Greetings :)
You can layout a JPanel with a layout manager, and do custom painting on top of it.
This does not prevent you from using pack()1.
The following mre 2 demonstrates painting a line on a JPanel using a GridLayout:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class NetworkViewPanel extends JPanel{
private final List<JLabel> labels;
public NetworkViewPanel() {
this.setLayout(new GridLayout(2, 2, 2, 2));
this.setPreferredSize(new Dimension(400,300));//used by pack()
labels = new ArrayList<>();
addLabels(new String[]{ "A", "B" , "C" , "D"});
}
private void addLabels(String[] text){
for(String t: text){
JLabel label = new JLabel(t);
label.setBorder(BorderFactory.createLineBorder(Color.BLUE));
label.setHorizontalAlignment(JLabel.CENTER);
add(label);
labels.add(label);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); //draw panel as layed out by layout manager
drawLines(g);
}
private void drawLines(Graphics g) {
//draw line between centers of first and last components
int x1 = labels.get(0).getBounds().x + labels.get(0).getBounds().width /2;
int y1 = labels.get(0).getBounds().y + labels.get(0).getBounds().height /2;
int x2 = labels.get(labels.size()-1).getBounds().x + labels.get(labels.size()-1).getBounds().width/2;
int y2 = labels.get(labels.size()-1).getBounds().y + labels.get(labels.size()-1).getBounds().height/2;
g.setColor(Color.RED);
g.drawLine(x1, y1, x2, y2);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.add(new NetworkViewPanel());
f.pack();
f.setVisible(true);
}
}
1 See: What does .pack() do?
2 Consider posting mre when asking or answering
Related
When I try to draw a JLabel or my GUI, whatever I add to my JFrame last is drawn and the rest is just never drawn or painted over. I would appreciate if you could help me find a solution to draw the JLabel at a specific place along with my GUI. I have heard about layout and how it could help me with that, but there were many different people saying different things about this subject. Here is my code.
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.JPanel;
import javax.swing.JFrame;
import static java.lang.System.*;
import java.awt.event.*;
import java.awt.Graphics.*;
public class Main extends JPanel
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double w = screenSize.getWidth();
double h = screenSize.getHeight();
static JFrame f = new JFrame("Tic-Tac-Toe");
static JPanel p = new JPanel();
int width = (int)w;
int height = (int)h;
int width1a = width/2 - 300;
int width2a = width/2 - 100;
int width3a = width/2 + 100;
int width4a = width/2 + 300;
int height1from = (int)height - 100;
int height1to = (int)height - (int)(height/1.05);
public void paintComponent(Graphics g)
{
super.paintComponent(g);
JLabel l = new JLabel("Hello World !");
f.add(l);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(10));
g.setColor(Color.black);
g2.drawLine(width1a, height1from, width1a, height1to);
g2.drawLine(width2a, height1from, width2a, height1to);
g2.drawLine(width3a, height1from, width3a, height1to);
g2.drawLine(width4a, height1from, width4a, height1to);
}
public static void main(String[] args)
{
Main m = new Main();
f.setSize(400,300);
f.setExtendedState(Frame.MAXIMIZED_BOTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
JLabel l = new JLabel("Hello World !");
f.add(p);
f.add(m);
}
}
Please tell me if I was unclear or anything. I just want the JLabel and the GUI drawings to appear on the JFrame. Feel free to suggest anything I should redo and thank you for your time!
You don't, ever, add components to a component from within a paint method. You should never modify the state of a component in any way from within a paint method, painting is for painting, nothing else.
See Painting in AWT and Swing and
Performing Custom Painting for more details about how painting works in Swing...
You are adding three components to the same position within a BorderLayout, generally, only the last component would normally be shown, as it's the one that is been managed by the BorderLayout
See Laying Out Components Within a Container and How to Use BorderLayout for more details.
You should also make sure that you are creating your UI from within the context of the Event Dispatching Thread, see Initial Threads for more details
Painting is also contextual to the component been painted, that is, the 0x0 is the top left corner of the component, any painting done beyond the visual range of the component is simply lost.
You should also avoid the use of static, generally, this is a good indication that you have a problem with your design, it gets especially messy within a UI. If you really want to hear me whinge about the evils of static, check out this answer
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel blue = new JPanel();
blue.setBackground(Color.BLUE);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Hello world"), BorderLayout.NORTH);
frame.add(new TestPane());
frame.add(blue, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
add(new JLabel("Hello World"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// This could actually be achieved using a EmptyBorder and a LineBorder
// but this demonstrates the point...
g2d.setColor(Color.RED);
g2d.drawRect(10, 10, getWidth() - 20, getHeight() - 20);
g2d.dispose();
}
}
}
I have a JPanel with a simple animated snow particle effect inside of a JFrame, and it works from on its own. But when I try and add another panel to it, it makes the effect of the snow stop. Can anyone help me with this? Is it a problem with layering, or something? Or is it an issue with my Layout Managers?
My Code:
package christmasfinal;
import java.awt.*;
import javax.swing.*;
public class ChristmasFinal extends JApplet {
public static void main(String[] args) {
JFrame frame = new JFrame();
TreePanel treePanel = new TreePanel();
frame.setSize(550, 420);
SnowBackgroundPanel snowPanel = new SnowBackgroundPanel(frame.getWidth(), frame.getHeight());
treePanel.setSize(200, 320);
snowPanel.setSize(frame.getWidth(), frame.getHeight());
snowPanel.setLayout(new BorderLayout());
frame.setLayout(new BorderLayout());
frame.add(snowPanel, BorderLayout.CENTER);
snowPanel.add(treePanel, BorderLayout.CENTER);
System.out.println(treePanel.getWidth() + " " + treePanel.getHeight());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setTitle("Christmas Final");
}
}
package christmasfinal;
import javax.swing.*;
import java.awt.*;
public class TreePanel extends JPanel{
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int[] treeX = {getWidth()/2, getWidth()/2-20, getWidth()/2-60, getWidth()/2-20,
getWidth()/2-40, getWidth()/2-80, getWidth()/2-20, getWidth()/2-60, getWidth()/2-100,
getWidth()/2+100,getWidth()/2+60, getWidth()/2+20, getWidth()/2+80,
getWidth()/2+40, getWidth()/2+20, getWidth()/2+60, getWidth()/2+20, getWidth()/2};
int[] treeY = {getHeight()/2-120, getHeight()/2-80, getHeight()/2-40, getHeight()/2-40,
getHeight()/2-20, getHeight()/2, getHeight()/2, getHeight()/2+40, getHeight()/2+60,
getHeight()/2+60, getHeight()/2+40, getHeight()/2, getHeight()/2, getHeight()/2-20,
getHeight()/2-40, getHeight()/2-40, getHeight()/2-80, getHeight()/2-120};
g.setColor(Color.GREEN);
g.fillPolygon(treeX, treeY, treeX.length);
g.setColor(new Color(102, 51, 0));
g.fillRect(getWidth()/2-20, getHeight()/2+60, 40, 40);
}
}
package christmasfinal;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import java.math.*;
public class SnowBackgroundPanel extends JPanel{
Random rand = new Random();
//Create ArrayList for SnowParticles
ArrayList<SnowParticle> snow = new ArrayList();
//Create animation timer
Timer timer = new Timer(7, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
public SnowBackgroundPanel(int width, int height){
setSize(width, height);
System.out.println(getHeight() + " " + getWidth());
for(int i=0; i<50; i++){
snow.add(new SnowParticle());
snow.get(i).x = rand.nextInt(getWidth()+1);
snow.get(i).y = 0-rand.nextInt(getHeight()+1);
}
timer.start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
//Set, paint, and move snow particles
for(int i=0; i<50; i++){
g.fillOval(snow.get(i).x, snow.get(i).y, 10, 10);
snow.get(i).y += 1;
if(snow.get(i).y > getHeight()){
snow.get(i).x = rand.nextInt(getWidth()+1);
snow.get(i).y = 0-rand.nextInt(getHeight()+1);
}
}
}
}
You're adding your TreePanel to the BorderLayout.CENTER position of the SnowPanel which will effectively cover up the SnowPanel, so it should be expected to cover SnowPanel's graphics and animation. Likely setting TreePanel to be non-opaque by calling setOpaque(false) on it will allow you to see through it:
TreePanel treePanel = new TreePanel();
treePanel.setOpaque(false);
Other issues with your code:
Why have ChristmasFinal extend JApplet when it has no applet code nor behaviors?
Avoid calling setSize(...) on anything as that is a dangerous thing to do.
Better to let the components size themselves based on their layout managers and preferredSizes.
If you absolutely need to set a size, better to override getPreferredSize()
You should avoid having program logic within a paintComponent(...) method since you never have complete control over when or even if paintComponent(...) gets called.
I suggest an entirely different approach:
SnowBackgroundPanel & TreePanel which extend JPanel should instead implement Drawable
The Drawable interface will have a single method draw(Graphics2D g, Dimension sizeOfParent)
In the draw() method, put what was in paintComponent()
In the single area designated for custom painting, (e.g. RenderingSurface extends JPanel) keep a collection of the drawn elements in a list that respects their order. e.g. if the first element is the BG, it is rendered first.
In the paintComponent() of RenderingSurface, iterate the collection of drawable elements and draw each one.
I've defined a new class LShapePanel which extends JPanel and which looks like an L.
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class LShapePanel extends JPanel{
public Color color;
public LShapePanel(Color color) {
this.color = color;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
/* coordinates for polygon */
int[] xPoints = {0,100,100,20,20,0};
int[] yPoints = {0,0,20,20,100,100};
/* draw polygon */
g2d.fillPolygon(xPoints, yPoints, 6);
}
}
I'd like to arrange two of these LShapePanels like this:
But I don't know how? Here is my code for arranging two LShapePanels in a row.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
public class DifferentShapes extends JFrame {
public DifferentShapes() {
setTitle("different shapes");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocation(500, 300);
JPanel panel = new JPanel();
/* create and add first L in red */
LShapePanel lsp1 = new LShapePanel(new Color(255,0,0));
lsp1.setPreferredSize(new Dimension(100,100));
panel.add(lsp1);
/* create and add second L in green*/
LShapePanel lsp2 = new LShapePanel(new Color(0,255,0));
lsp2.setPreferredSize(new Dimension(100,100));
panel.add(lsp2);
add(panel);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
DifferentShapes df = new DifferentShapes();
df.setVisible(true);
}
});
}
}
And the result:
You need to use layout manager to arrange the components in the JFrame. According to this turorial, the content pane, which actually contains the components you put into JFrame, uses Borderlayout by default. In an "L" shape as the LShapePanel looks, it's actually a rectangle(every component in swing is a rectangle, as a matter of fact) with part of it transplant. So if you want to arrange the panels in the way you want, they will have to overlap with each other. Different kinds of layout managers use different layout strategies, and Borderlayout won't allow components to overlap, so you have to change to another layout manager. Sorry that I don't know any layout manager that allows components to overlap, but you can use JLayeredPane to achieve you goal. Add a JLayeredPane to the JFrame and then add the LShapePanels to the JLayeredPane.
Sorry, layout manager enthusiasts, but I can't think of any way other than using setLocation and a null layout manager. Here's a demonstration:
setLayout(null);
LShapePanel lsp1 = new LShapePanel(new Color(255,0,0));
lsp1.setPreferredSize(new Dimension(100,100));
lsp1.setLocation(0,0);
add(lsp1);
LShapePanel lsp2 = new LShapePanel(new Color(0,255,0));
lsp2.setPreferredSize(new Dimension(100,100));
lsp2.setLocation(30,30);
add(lsp2);
If you create a JScrollPane that has a viewport larger than the JScrollPane's component, it displays that component in the upper left.
Is there any way to change this behavior so it displays the component centered?
example program below.
clarification:
I have a component which has (width, height) = (cw,ch).
I have a JScrollPane with a viewport which has (width, height) = (vw, vh).
The component may become larger or smaller. I would like a way to use the scrollbars to position the component's centerpoint relative to the viewport's center point, so if the one or both of the component's dimensions are smaller than the viewport, the component shows up in the center of the viewport.
The default scrollpane behavior positions the component's upper left corner relative to the viewport's upper left corner.
All I'm asking is how to change the reference point. I am not sure how easy this is to do with the default JScrollPane, so if it's not easy, then I'll learn what I can and think of a different approach.
package com.example.test.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class SimpleScroller extends JFrame {
static class Thingy extends JPanel
{
private double size = 20.0;
#Override public Dimension getPreferredSize() {
int isize = (int) this.size;
return new Dimension(isize, isize);
}
#Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
int[] x = {0, 100, 100, 0, 0, 75, 75, 25, 25, 50};
int[] y = {0, 0, 100, 100, 25, 25, 75, 75, 50, 50};
Graphics2D g2d = (Graphics2D) g;
AffineTransform at0 = g2d.getTransform();
g2d.scale(size/100, size/100);
g.drawPolyline(x, y, x.length);
g2d.setTransform(at0);
}
public void setThingySize(double size) {
this.size = size;
revalidate();
repaint();
}
public double getThingySize() { return this.size; }
}
public SimpleScroller(String title) {
super(title);
final Thingy thingy = new Thingy();
setLayout(new BorderLayout());
add(new JScrollPane(thingy), BorderLayout.CENTER);
final SpinnerNumberModel spmodel =
new SpinnerNumberModel(thingy.getThingySize(),
10.0, 2000.0, 10.0);
spmodel.addChangeListener(new ChangeListener() {
#Override public void stateChanged(ChangeEvent e) {
thingy.setThingySize((Double) spmodel.getNumber());
}
});
add(new JSpinner(spmodel), BorderLayout.NORTH);
}
public static void main(String[] args) {
new SimpleScroller("simple scroller").start();
}
private void start() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
}
Put a JPanel into the scroll-pane
Set the layout of the panel to a GridBagLayout.
Put one component into the panel with no constraint. It will be centered.
This is the technique used in the Nested Layout Example, which places the red/orange image into the center of the parent.
I simply added a JPanelto the JScrollPane to which I added the THINGY JPanel. Hope this is what you wanted :
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class SimpleScroller extends JFrame {
static class Thingy extends JPanel
{
private double size = 20.0;
#Override public Dimension getPreferredSize() {
int isize = (int) this.size;
return new Dimension(isize, isize);
}
#Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
int[] x = {0, 100, 100, 0, 0, 75, 75, 25, 25, 50};
int[] y = {0, 0, 100, 100, 25, 25, 75, 75, 50, 50};
Graphics2D g2d = (Graphics2D) g;
AffineTransform at0 = g2d.getTransform();
g2d.scale(size/100, size/100);
g.drawPolyline(x, y, x.length);
g2d.setTransform(at0);
}
public void setThingySize(double size) {
this.size = size;
revalidate();
repaint();
}
public double getThingySize() { return this.size; }
}
public SimpleScroller(String title) {
super(title);
final Thingy thingy = new Thingy();
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.add(thingy);
JScrollPane scroll = new JScrollPane();
scroll.setViewportView(panel);
add(scroll, BorderLayout.CENTER);
final SpinnerNumberModel spmodel =
new SpinnerNumberModel(thingy.getThingySize(),
10.0, 2000.0, 10.0);
spmodel.addChangeListener(new ChangeListener() {
#Override public void stateChanged(ChangeEvent e) {
thingy.setThingySize((Double) spmodel.getNumber());
}
});
add(new JSpinner(spmodel), BorderLayout.NORTH);
}
public static void main(String[] args) {
new SimpleScroller("simple scroller").start();
}
private void start() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
}
Here is the output :
Accepting your both comments, but
yes... although I'd really like to arbitrarily position it
there are
extract or to create own JViewport
important methods to avoiding flickering or jumping on the JViewport
JViewport.setScrollMode(JViewport.BLIT_SCROLL_MODE);
JViewport.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
JViewport.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
use GlassPane (is very simple to set for possition to the desired Point or/and Dimmension)
and
I don't want to paint to the JViewport, at least not directly -- My real code is a component subclassed from JPanel, as in my example, but it also has other GUI elements in it.
you can use JXLayer (Java6) or parts of methods from JXLayer implemented to the JLayer (Java7) directly
could be too hard, but in all cases you can overlay whatever with JLabel
Notice
all my suggestion to consume MouseEvent by default, J(X)Layer and JLabel with KeyEvents too, but there no issue with redispatch events from ---> to another JComponent
EDIT
wait: no, I don't want to paint the spiral (what you called "snake") in the center of the JScrollPane; I want to paint my component and have my component be displayed in the center of the JScrollPane.
your JPanel could be wider than JViewport by default
a) JPanel returns Dimension
b) JViewport return Dimension
then without any issue, flickering or freeze
a) you can centering Dimmension from JPanel (Point) to the center of JViewport (Point)
b) if is there JComponent you can move the JViewport to any getBounds() tha returned JComponent or Point from JPanel inside JScrollPane
With the suggestion from Andrew, you can't have the view smaller than the viewport (and still centered).
The cleanest way is doing it directly from the layout manager, overriding ViewportLayout. There is an implementation in the source of:
http://www.randelshofer.ch/multishow
Look for the class ZoomableViewportLayout, which does the job perfectly.
I have been having a some issues with Swing lately. I'm trying to make something like in the image below on the fly, to illustrate the data structures for algorithms.
(source: ius.edu)
All that I was trying to do in the following class is draw out some rectangles with numbers on them. and translate them, however the last rectangle draws at 0,0. I'm stumped.
If you add the JPanel (commented out) after the loop then it draws as expected.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawingRect {
public static void main(String[] args) {
DrawingRect d = new DrawingRect();
}
public DrawingRect() {
JFrame frame = new JFrame("Drawing a rect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel swingPanel = new JPanel();
swingPanel.setPreferredSize(new Dimension(500, 500));
swingPanel.setVisible(true);
swingPanel.setLayout(new BorderLayout(0, 0));
int base = 15;
for (int i = 1; i <= 25; i++) {
Graphic re = new Graphic(i);
//translating the graphic
re.setBounds(base + 30 * i, base + 20 * i, 110, 110);
swingPanel.add(re);
}
// if say I add a JPanel in here as the last element
// then the boxes will draw correctly.
//swingPanel.add(new JPanel());
swingPanel.setPreferredSize(new Dimension(800, 600));
frame.getContentPane().add(swingPanel);
frame.pack();
frame.setVisible(true);
}
public class Graphic extends JComponent {
private static final long serialVersionUID = 1L;
private static final int PREF_W = 100;
private static final int PREF_H = 100;
int id;
public Graphic(int id) {
this.id = id;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
g2.setColor(Color.black);
g2.drawRoundRect(0, 0, 30, 30, 20, 20);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("", Font.PLAIN, 13);
g2.setFont(font);
g2.drawString("" + id, 15, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
}
The default layout of JPanel is FlowLayout, but you're positioning components as if the layout were null. Moreover, you're drawing content that a nested component could do automatically.
Instead, add several JPanels containing JLabel's to a containing panel having GridLayout. Use empty panels as required. Override paintComponent() in the outer panel to draw connecting lines.
Addendum: Anytime one is tempted to use Absolute Positioning, JInternalFrame may be an alternative. Related examples may be found here and here.
Addendum: If the project grows beyond the prototype stage, also consider a Custom Layout Manager.
It is because you are using BorderLayout. You can test this by changing your add line to include a specific layout location: swingPanel.add(re,BorderLayout.SOUTH).
As for a solution, why not draw all the rectangles on a picture and update it at the end of the loop? Or is the adding to JPanel part of your demonstration?