It shows the line without jpanel on jframe, but it doesn't when I add it to jpanel. I've tried setting the layout manager of jpanel to null but no result. I want to use JComponents for drawing lines because I want them clickable.
Main.java file:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
//Parent Panel
JPanel panel = new JPanel();
panel.setBackground(Color.YELLOW);
panel.setLayout(null);
//Add Line To Panel
Line line = new Line(new Point2D.Double(20,20), new Point2D.Double(180,180));
panel.add(line);
panel.repaint();
frame.add(panel);
frame.setVisible(true);
}
}
class Line extends JComponent {
private final Point2D start, end;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.setStroke(new BasicStroke(2.0F));
g2.draw(new Line2D.Double(start,end));
}
public Line( Point2D start, Point2D end){
this.start = start;
this.end = end;
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("mouse clicked");
}
});
}
}
It shows the line without jpanel on jframe, but it doesn't when I add it to jpanel
Swing components are responsible for determining their own preferred size.
When you add a component to a panel, the layout manager will then set the size/location of the component based on the rules of the layout manager.
When you add a component to the frame you really add it to the content pane of the frame which is a Jpanel which uses a BorderLayout by default. So the component is sized to fill the space available in the frame.
panel.setLayout(null);
You then added the component to a panel with a null layout. Now you are responsible for setting the size/location of the component. If you don't the size is (0, 0) so there is nothing to paint.
You should override the getPreferredSize() method of your class to return the preferred size of the component. Then layout managers can do their job.
If you really need a null layout, then the size of the component should be set in the application code, not it the Line class itself.
But now my line has a big container that listens for any clicks,
If you want hit detection then you override the contains(...) method.
Here is a basic example implementing the above suggestions:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Line extends JComponent
{
private Line2D.Double line;
public Line( Point2D start, Point2D end)
{
line = new Line2D.Double(start, end);
addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
System.out.println("mouse clicked");
}
});
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor( Color.BLUE );
g2.setStroke( new BasicStroke(2.0F) );
g2.draw( line );
}
#Override
public Dimension getPreferredSize()
{
Rectangle bounds = line.getBounds();
int width = bounds.x + bounds.width;
int height = bounds.y + bounds.height;
return new Dimension(width, height);
}
#Override
public boolean contains(int x, int y)
{
double distance = line.ptSegDist( new Point2D.Double(x, y) );
return distance < 2;
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
//Parent Panel
JPanel panel = new JPanel();
panel.setBackground(Color.YELLOW);
//Add Line To Panel
Line line = new Line(new Point2D.Double(20,20), new Point2D.Double(180,180));
panel.add(line);
panel.repaint();
frame.add(panel);
frame.setVisible(true);
}
}
Add custom size in Line constructor.
public Line( Point2D start, Point2D end){ ...
this.setSize(200, 200); }
Updated to fit also with painted Graph
Advice to change from JComponent to JPanel in order to see background
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
//Parent Panel
JPanel panel = new JPanel();
panel.setSize(300,300);
frame.add(panel);
panel.setBackground(Color.YELLOW);
panel.setLayout(null);
//Add Line To Panel
Line line = new Line(new Point2D.Double(20,20), new Point2D.Double(180,180));
panel.add(line);
frame.setVisible(true);
}
}
class Line extends JPanel {
private final Point2D start, end;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(Color.RED);
g2.setColor(Color.BLUE);
g2.setStroke(new BasicStroke(2.0F));
g2.draw(new Line2D.Double(start,end));
Rectangle r = g2.getClipBounds();
System.out.println(r.x+":"+r.y);
}
public Line( Point2D start, Point2D end){
this.start = start;
this.end = end;
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("mouse clicked at "+e.getX()+":"+e.getY());
}
});
int max_x = (int) Math.max(start.getX(), end.getX());
int max_y = (int) Math.max(start.getY(), end.getY());
System.out.println("max x="+max_y+",y="+max_y);
setSize(max_x,max_y);
setVisible(true);
setBackground(Color.GREEN);
}
}
Note: Only inside_green clicks allowed !
Related
So I am using a JFrame object to open up a window and add a bunch of graphics first I am adding an image then I am trying to add some lines, But it seems like the line start from the Y center of the previous image I would like for it to start at the top of the page
here is my code for the JFrame:
JFrame f = new JFrame();
JLabel trebeclef = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("Some image")));
Draw d = new Draw();
f.add(trebeclef);
f.add(d);
f.setSize(1000,1000);
f.getContentPane().setBackground(Color.white);
f.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
here is the code for the Draw class
public void paint(Graphics g2) {
super.paintComponent(g2);
Graphics2D g = (Graphics2D) g2;
g.setStroke(new BasicStroke(2));
g.drawLine(0, 0, 100, 0);
}
it results in this
Any help appreciated, thanks
Trying to layout components like this isn't the easiest thing to to, especially when you consider the complexities of JLabel and the possibilities of other layout constraints.
If you have the image and you're drawing the lines via custom painting, I would just custom paint the whole thing
Starting with...
We can produce something like...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new ClefWithLinesPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class ClefWithLinesPane extends JPanel {
private BufferedImage trebbleClef;
public ClefWithLinesPane() throws IOException {
trebbleClef = ImageIO.read(getClass().getResource("/images/ClefLines.png"));
setBackground(Color.WHITE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = 0;
int y = (getHeight() - trebbleClef.getHeight()) / 2;
g2d.drawImage(trebbleClef, x, y, this);
int[] lines = new int[] {
30, 60, 89, 120, 149
};
x = trebbleClef.getWidth();
g2d.setStroke(new BasicStroke(2));
for (int line = 0; line < lines.length; line++) {
y = lines[line];
g2d.drawLine(x, y, getWidth(), y);
}
g2d.dispose();
}
}
}
But... as you can see, the lines don't "quite" match up, now this is simply an issue with source image and you could spend some time cleaning it up, or, you could just dispense with the lines of the clef itself and do those you're self, for example...
Starting with...
We could produce something like...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new ClefWithOutLinesPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class ClefWithOutLinesPane extends JPanel {
private BufferedImage trebbleClef;
public ClefWithOutLinesPane() throws IOException {
trebbleClef = ImageIO.read(getClass().getResource("/images/Clef.png"));
setBackground(Color.WHITE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int minLineY = 30;
int maxLineY = 150;
int lineSpacing = (maxLineY - minLineY) / 4;
int x = 10;
g2d.setStroke(new BasicStroke(8));
g2d.drawLine(x, minLineY + 3, x, maxLineY - 3);
int y = (getHeight() - trebbleClef.getHeight()) / 2;
g2d.drawImage(trebbleClef, x + 10, y, this);
g2d.setStroke(new BasicStroke(2));
for (int line = 0; line < 5; line++) {
y = minLineY + (lineSpacing * line);
g2d.drawLine(x, y, getWidth(), y);
}
g2d.dispose();
}
}
}
Adds after setLayout. One often uses an overloaded add with an extra parameter for a layout's specific constraint.
By default the content pane the frame's adds are done upon, has a BorderLayout with center, left and so on.
The horizontal "line" in a flow is vertically centered. Setting a preferred height ensures a line component is filled up.
d.setPreferredSize(new Dimension(100, 1000));
Of course an other layout might serve better; depending on what you want - just experiment.
I am starting with Java and want to make a simple pong game to get into the ways of displaying stuff in java. I have created 2 classes that both extend JPanel and call the repaint() function every 16.6 milliseconds. I added both to a JPanel which I added to the frame, but only the component I added first displays.
I've tried to revalidate() after repaint() in both classes and made sure that the Timer actually works and that it's actionPerformed() method is actually called.
This is the main method:
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame("Pong");
//...
JPanel mainPanel = new JPanel();
mainPanel.add(new Player());
mainPanel.add(new Ball(frameWidth/2, frameHeight/2 -40));
frame.add(mainPanel);
}
}
This is the important code for the classes (It's basically the same for both of them):
public class Player extends JPanel {
public Player(){
setPreferredSize(new Dimension(Main.frameWidth, Main.frameHeight));
setBackground(Color.BLACK);
new Timer(1000/60, new ActionListener(){
public void actionPerformed(ActionEvent e){
update();
repaint();
}
}).start();
}
//...
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
}
}
(Of coure I left things like #Override or unneseccary functions out to shorten the code)
This code only paints the Player, altough I want it to display all the components of mainPanel.
This is an example that you can (hopefully) run. I had to split it up into 3 files, since I suck at anonymus classes:
Main.java
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame("Pong");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 800);
JPanel mainPanel = new JPanel();
mainPanel.add(new Player());
mainPanel.add(new Ball());
frame.add(mainPanel);
frame.setVisible(true);
}
}
///////
Player.java
//////
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Player extends JPanel{
private int x = 20, y = 300, width = 20, height = 100;
public Player(){
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000/60, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
}
}
//////
Ball.java
//////
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Ball extends JPanel{
private int x = 20, y = 300, width = 20, height = 100;
public Ball(){
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000/60, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
}
}
In method paintComponent() of class Player, you paint the exact same Rectangle each time. In order to achieve animation, each time you paint the rectangle you need to change either its size or location or both. What do you expect the Player to do? Should it move up and down along the left edge of the window? Have you seen the lesson entitled How to Use Swing Timers which is part of Oracle's Java Tutorial?
EDIT
I see now that Player hides Ball, because of the default layout manager of JPanel. The below code is essentially the code you posted but I set GridLayout as the layout manager for mainPanel. Also, a java source code file may contain more than one class but exactly one class must be public. Hence in the below code only class Main is public.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Pong");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel(new GridLayout(0, 2));
mainPanel.add(new Player());
mainPanel.add(new Ball());
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class Player extends JPanel {
public Player() {
setBorder(BorderFactory.createLineBorder(Color.RED, 2, false));
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000 / 60, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(20, 100, 20, 100);
}
}
class Ball extends JPanel {
public Ball() {
setBorder(BorderFactory.createLineBorder(Color.CYAN, 2, false));
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000 / 60, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(300, 300, 10, 10);
}
}
And here is a screen capture of the GUI...
I just realized that if I extend my window manually, the second JPanel shows up under the one responsible for the Player! This means that I'll need to set the Panels position somehow, right?
#Abra
This question already exists:
How to set size for custom-made panel that will work with gridbaglayout?
Closed 6 years ago.
I have one panel whit gridBagLayout and second with null gridlayout. When I add that to main panel, and main panel to frame one panel disappears. Why is that? And how to add two panels with different layouts setings in one frame?
Here is the code main #Beowolve:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PrikazGUI {
JFrame frejm;
JPanel k;
JButton b1,b2;
public PrikazGUI(){
frejm = new JFrame("Lala");
k = new JPanel();
KvadratPravi p = new KvadratPravi();
JPanel grid = new JPanel();
grid.setLayout(new GridBagLayout());
grid.add(p);
// Kvadrat l = new Kvadrat();
JosJedanKvadrat jos = new JosJedanKvadrat();
// k.setLayout(null);
// k.setBounds(0, 444,444, 445);
k.add(jos);
k.add(grid);
JPanel main = new JPanel();
main.setLayout(null);
k.setBounds(0, 0,1000, 1900);
main.setBounds(0, 0,1000, 1900);
main.add(k);
frejm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frejm.setSize(1900, 1000);
frejm.getContentPane().add(main);
// frejm.getContentPane().add(k);
// frejm.pack();
frejm.setVisible(true);
}
public static void main(String[] args) {
PrikazGUI a = new PrikazGUI();
}
}
Second class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JPanel;
public class KvadratPravi extends JPanel {
int sizeH = 60;
int sizeW = 60;
public GridBagConstraints cst = new GridBagConstraints();
public KvadratPravi() {
JPanel j = new JPanel();
j.setLayout(new GridBagLayout());
cst.gridx = 0;
cst.gridy = 0;
add(j,cst);
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.setColor(Color.PINK);
g.drawRect(0, 0, sizeH, sizeW);
g.fillRect(0, 0, sizeH, sizeW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(sizeH,sizeW);
}
}
Third class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
public class JosJedanKvadrat extends JPanel {
int sizeH = 60;
int sizeW = 60;
int x,y;
public JosJedanKvadrat() {
setBounds(33, 44,444, 445);
JPanel j = new JPanel();
setLayout(null);
add(j);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if(!e.isMetaDown()){
x = e.getX();
y = e.getY();
}
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
if(!e.isMetaDown()){
Point p = getLocation();
setLocation(p.x + e.getX() - x,
p.y + e.getY() - y);
}
}
});
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawOval(0, 0, sizeH, sizeW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(sizeH,sizeW);
}
}
So I whant second class be in center of panel,and to have gridBagLayout, and third class I whant to move around the objects,so that class dont have gridlayout...when I and that two panels to main pane its seems that second class whit gridBagLayout does not working.
You are currently adding two JPanel into a JFrame.
JFrame f = new JFrame();
This frame, by default, use a BorderLayout. So if you call f.add(new Panel()); multiple time only the last one will be visible since the center area of this layout can only show one JComponent. You need to use a different layout.
I have been trying to learn how to draw to a Jpanel for a game. I want to draw to it from different classes (like a class that manages maps and a class that manages player models).
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main
{
public static void main (String[] args)
{
JFrame frame = new JFrame ("Java Game");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (1000, 600);
JPanel panel = new JPanel();
panel.setBackground (Color.WHITE);
Dimension size = new Dimension(1000,500);
panel.add (new Player()); // Class with paintComponent method.
panel.setPreferredSize(size);
panel.setBackground(Color.BLUE);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
}
next class
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
#SuppressWarnings ("serial")
public class Player extends JComponent
{
int x = 50;
int y = 450;
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.setColor (Color.BLACK);
g.fillRect (x, y, 50, 50);
}
}
You probably want to extend JPanel. It's already opaque, and it can handle the background color for you. Also give your panel a size like they do here, then you can do the drawing relative to the size.
Player p = new Player();
p.setBackground(Color.cyan);
frame.add(p);
frame.pack();
frame.setVisible(true);
…
public class Player extends JPanel {
private static final int X = 320;
private static final int Y = 240;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(getWidth() / 2 - 25, getHeight() / 2 - 25, 50, 50);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(X, Y);
}
}
I'm trying to build a simple paint tool. The mouseDrag events creates a new ellipse and causes my JPanel to repaint().
This works fine so far.
However, if I press any button (or any other UI component) before firing the mouseDrag event for the first time, the button is painted in the upper left corner of my panel.
I have isolated the code into this test application:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame
{
public Test()
{
final JPanel paintPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setPaintMode();
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(100, 100, 10, 10);
}
};
paintPanel.setPreferredSize(new Dimension(300,300));
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e)
{
paintPanel.repaint();
}
});
this.setLayout(new FlowLayout());
this.add(paintPanel);
this.add(new JButton("Dummy"));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String... args)
{
new Test();
}
}
A Screenshot for "seeing" the problem in my Main application
+1 to #MadProgrammer's answers.
You should have super.paintComponent(..) as the first call in your overriden paintComponent()
Do not extend JFrame unnecessarily
Create and minipulate Swing components via EDT
Dont call setPrefferedSize() rather override getPrefferedSize()
Here is an example which incorporates my advice's and #MadProgrammer's:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
JFrame frame;
public Test() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final PaintPanel paintPanel = new PaintPanel();
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
paintPanel.addRect(e.getX(), e.getY());
}
});
frame.setLayout(new FlowLayout());
frame.add(paintPanel);
frame.add(new JButton("Dummy"));
frame.pack();
frame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class PaintPanel extends JPanel {
public PaintPanel() {
addRect(100, 100);
}
ArrayList<Rectangle> rects = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaintMode();
for (Rectangle r : rects) {
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(r.x, r.y, r.width, r.height);
}
}
public void addRect(int x, int y) {
rects.add(new Rectangle(x, y, 10, 10));
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
You're not calling super.paintComponent.
The graphics context used for a paint cycle is shared between all the components begin painted, this means if you don't take care to clear it before painting onto, you will end up with what ever was painted before you.
One of the jobs of paintComponent is to prepare the graphics for painting