I'm doing a selection tool and I've come with these solutions, in the first using the JPanel getGraphics method I draw a oval wherever the mouse been dragged, in the second I override the paintComponent method to draw the oval.
When I execute the first one there's flickering while dragging the mouse and the drawing is poor, while with the second approach runs perfect. Why does this happen?, if I quit repaint in the first solution it draws the ovals and doesn't 'delete' them.
What are best practices to do something like this?, am I missing something when I draw with getGraphics?.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestGetGraphics extends JFrame {
JPanel canvas;
Painter painter;
class Painter{
void paint( Graphics2D g, Point p ){
g.drawOval(p.x, p.y, 30, 30);
}
}
public TestGetGraphics(){
super();
canvas = new JPanel();
painter = new Painter();
canvas.setPreferredSize( new Dimension(400, 400) );
canvas.setBackground(Color.WHITE);
canvas.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent me){
painter.paint((Graphics2D) canvas.getGraphics(), me.getPoint());
canvas.repaint();
}
});
add( canvas );
setVisible(true);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestGetGraphics();
}
});
}
}
This is the paintComponent approach:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestPaintComponent extends JFrame {
JPanel canvas;
Painter painter;
class Painter{
Point p;
void paint( Graphics2D g ){
if( p != null )
g.drawOval(p.x, p.y, 30, 30);
}
void setPoint( Point p ){
this.p = p;
}
}
public TestPaintComponent(){
super();
canvas = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
painter.paint((Graphics2D) g);
}
};
painter = new Painter();
canvas.setPreferredSize( new Dimension(400, 400) );
canvas.setBackground(Color.WHITE);
canvas.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent me){
painter.setPoint(me.getPoint());
canvas.repaint();
}
});
add( canvas );
setVisible(true);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestPaintComponent();
}
});
}
}
Don't call getGraphics() on a component. Instead, extend the component and override paintComponent(). More info here: http://docs.oracle.com/javase/tutorial/uiswing/painting/
Related
I wonder why the repiant() method is not working as intended. My Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class RightPanel extends JPanel implements ActionListener{
JButton buttono;
JButton buttonu;
MyFrame frame;
ButtomPanel s;
public RightPanel(MyFrame frame){
super();
this.frame=frame;
s= new ButtomPanel(frame);
this.setPreferredSize(new Dimension((frame.getWidth()/3),frame.getHeight()));
setBackground(Color.green);
setLayout(new BorderLayout());
buttono = new JButton ("up");
buttonu = new JButton ("down");
buttono .addActionListener(this);
buttonu .addActionListener(this);
add(buttono , BorderLayout.NORTH);
add(buttonu , BorderLayout.SOUTH);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource()==buttono) {
System.out.println("Up");
s.x=s.x+10;
s.repaint();
}
}
I want to Repaint following class:
import java.awt.Color;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ButtomPanel extends JPanel {
MyFrame frame;
BufferedImage image;
boolean geklickt=false;
public static int x=0;;
public ButtomPanel(MyFrame frame) {
super();
this.frame=frame;
this.setPreferredSize(new Dimension(((frame.getWidth()/3)*2),585));
setBackground(Color.blue);
java.net.URL resource = getClass().getResource("/resources/siegel.jpg");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
e.printStackTrace();
}
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(image, 150+x, 150+x, 150, 150, null);}
}
}
I want to change with the ActionListener in the RightPanel Class the x from the BottomPanel Class and then repaint it, but it doesnt work. I can raise the x, but s.repaint() does not call the paint-Method.
s is never added to anything, so it will never be painted.
this.setPreferredSize(new Dimension((frame.getWidth()/3),frame.getHeight())); is a horribly bad idea. The window should be conforming to the size of the components, not the other way round. In fact, there's never really a good reason to expose MyFrame to the components this way, it provides these components control over MyFrame which they should never have.
java.net.URL resource = getClass().getResource("/resources/siegel.jpg");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
e.printStackTrace();
}
is a bad idea. The class should be throwing the exception to those using it, so that they know something has gone wrong. Doing it this way not only consumes the error in a way which is difficult to trace, but also sets you up for a NullPointerException when you call g.drawImage(image, 150+x, 150+x, 150, 150, null)
Don't override paint
public void paint(Graphics g) {
super.paint(g);
g.drawImage(image, 150+x, 150+x, 150, 150, null);
}
prefer paintComponent instead. paint is actually a very complex method. See Painting in AWT and Swing and Performing Custom Painting for more details
public static int x=0; is a bad idea for a three reasons:
static is not your friend. What happens when you have more than one instance of ButtomPanel? Generally speaking, when you use static in this way, it's a red flag telling you that your design is wrong.
public is providing uncontrolled access to the property. This is generally discouraged and you could be preferring to use setters and getters to interact with the property.
JPanel already has a x property, which could make it confusing (ie if if someone used getX instead of x). Better to rename it to something like imageX of imageXOffset.
Runnable example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.JButton;
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 RightPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class RightPanel extends JPanel implements ActionListener {
JButton buttono;
JButton buttonu;
ButtomPanel s;
public RightPanel() throws IOException {
super();
s = new ButtomPanel();
setBackground(Color.green);
setLayout(new BorderLayout());
buttono = new JButton("up");
buttonu = new JButton("down");
buttono.addActionListener(this);
buttonu.addActionListener(this);
add(buttono, BorderLayout.NORTH);
add(buttonu, BorderLayout.SOUTH);
add(s);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == buttono) {
System.out.println("Up");
s.addToImageXOffset(10);
}
}
}
public class ButtomPanel extends JPanel {
private BufferedImage image;
private int imageXOffset = 0;
public ButtomPanel() throws IOException {
super();
setBackground(Color.blue);
image = ImageIO.read(getClass().getResource("/images/Heart.png"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void addToImageXOffset(int delta) {
setImageXOffset(getImageXOffset() + delta);
}
public void setImageXOffset(int imageXOffset) {
this.imageXOffset = imageXOffset;
repaint();
}
public int getImageXOffset() {
return imageXOffset;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
g.drawImage(image, 150 + imageXOffset, 150 + imageXOffset, this);
}
}
}
I have imported from maven what title of the question says
the problem is to the point where I get graphics from my canvas(awt one)
and add it to jpanel this does not seem to be drawed
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
public class CELSIUS {
private JButton button1;
private JPanel panel1;
public java.awt.image.BufferedImage bf;
public Canvas cnv;
public JFrame jf;
private boolean annadido=false;
public CELSIUS() {
panel1.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
System.out.println("Hallo\n");
}
});
}
private void createUIComponents() {
panel1 = new JPanel();
button1 = new JButton("OK");
bf=new BufferedImage(100,100,BufferedImage.TYPE_BYTE_BINARY);
Graphics gc=bf.getGraphics();
gc.setColor(Color.BLACK);
gc.fillRect(0,0,100,100);
cnv=new Canvas();
cnv.setSize(100,100);
gc.setColor(Color.white);
gc.drawString("francisco",10,10);
gc.dispose();
}
public static void main(String []args){
JFrame jf=new JFrame();
CELSIUS mycell=new CELSIUS();
mycell.jf=jf;
mycell.jf.setSize(500,500);
jf.setContentPane(mycell.panel1);
mycell.cnv.getGraphics().drawImage(mycell.bf,0,0,jf);
jf.getContentPane().add(mycell.cnv);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
}
}
so what happens
???
note: if I add it multiple times in the mouse move handler sometimes works as intended
showing a blinking Francisco on white over black background
Here is the right way:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.plaf.PanelUI;
import static javax.swing.border.BevelBorder.*;
public class main12 {
public static void main(String [] a){
mijpanel a1=new mijpanel();
JFrame jmain =new JFrame("Hello world");
jmain.add(a1);
jmain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
a1.setVisible(true);
jmain.pack();
jmain.setVisible(true);
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
a1.add(new Label("This is"));
a1.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
jmain.setTitle("Moving "+e.getX()+" "+e.getY());
}
});
return;
}
}
class mijpanel extends JPanel{
public
BufferedImage inner;
public mijpanel(){
super();
setBorder(BorderFactory.createBevelBorder(RAISED));
inner=new BufferedImage(100,100,BufferedImage.TYPE_BYTE_BINARY);
}
#Override
public Dimension getPreferredSize(){
return new Dimension(500,500);
}
#Override
public void paint(Graphics g){
super.paint(g);
/*System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());*/
//System.out.println(getUI());
if(SwingUtilities.isEventDispatchThread())
{
Graphics g3=inner.getGraphics();
g3.setColor(Color.black);
g3.fillRect(00,0,100,100);
g3.setColor(Color.white);
Font myfont1=g3.getFont();
//System.out.println( myfont1.getFontName());
g3.drawString("My text",0,20);
g3.dispose();
}
g.setXORMode(Color.white);
System.out.println(g.getColor());
g.drawImage(inner,0,0,this);
g.drawString("Custom painting",50,50);
g.setColor(Color.RED);
g.setXORMode(Color.white);
g.drawString("To see ...and given color",150,150);
g.setColor(Color.green);
g.fillRect(50,80,200,200);
//g.fillRect(50,80,200,200);
}
}
as you can see i have removed all unneccesary library dependences
So I am making a little game to learn some graphical java and I am having trouble with a button. It is drawing 2, one is the correct size and in the correct location and then there is a very small button centered at the top of the application. THere should only be the one button at (0,0,200,50). I do not know what is wrong but here is the code for the button, if you need something more then this let me know!
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
EDIT1: the 2 classes where error will be: board.java:
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Board extends JPanel {
public Board() {
}
#Override
public void paintComponent(Graphics g) {
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
}
private void drawRectangle(Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawRect(x, y, width, height);
}
}
and the main:
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class main extends JFrame {
public main() {
initUI();
}
private void initUI() {
add(new Board());
setSize(800, 600);
setTitle("Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
main ex = new main();
ex.setVisible(true);
}
});
}
}
If you try to resize window, you will see that buttons are spawning.
This happens because of your paintComponent method, which is called every painting iteration.
You should move button addition, for example, to constructor which is called once:
public Board() {
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
}
I have a two class project, one class reads one file, and checks each entry in said file against a website, and posts the return data in another file.
If the return data says true(for example), the data point in the file is flashed on the screen. This functionality works.
I invoke this through the following if statement within a while loop.
if (!query.text().contains("unavailable") && !query.text().contains("at least 3 characters long to acquire.") && line != null) {
HitBox h = new HitBox(line); //GUI Class.
fos.write(query.text().getBytes());
fos.write("\n".getBytes());
fos.flush();
}
Below is my GUI class.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
public class HitBox {
private Timer t;
JWindow frame = new JWindow();
public HitBox(String s) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
frame.setAlwaysOnTop(true);
t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e2) {
SwingUtilities.getWindowAncestor(frame.getComponent(0))
.dispose();
}
});
}
});
frame.setBackground(new Color(0, 0, 0, 0));
TranslucentPane tp = new TranslucentPane(s);
frame.setContentPane(tp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
t.start();
}
}
class TranslucentPane extends JPanel {
public TranslucentPane(String s) {
add(new JLabel(s));
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.85f));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
This happens using the same set of input data, even if I override the web query, and just return a set value, # a random point in runtime, a JWindow will appear, a nullpointer will be thrown (# my call of the start method of my timer object).
This leads me to believe I'm implementing the timer incorrectly; I'm intrigued by how with consistent data, and return, there is variation in the point it throws the nullpointer.
Exception in thread "main" java.lang.NullPointerException
at HitBox.<init>(HitBox.java:51)
at OriginalGangster.main(OriginalGangster.java:38)
You're not starting your GUI on the GUI thread. You need to move it into the Runnable and be sure to start the Timer after it has been constructed.
e.g.,
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
public class TestHitBox {
public static void main(String[] args) {
String text = "Hello world! This is Hovercraft!";
int seconds = 5;
float composite = 0.85f;
float points = 48f;
HitBox.showMessage(text, seconds, composite, points);
}
}
class HitBox {
public static void showMessage(final String text, final int seconds, final float composite, final float points) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
final JWindow frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
TranslucentPane tp = new TranslucentPane(text, composite, points);
frame.setContentPane(tp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
new Timer(1000 * seconds, new TimerListener(frame)).start();
}
});
}
}
class TimerListener implements ActionListener {
private JWindow frame;
public TimerListener(JWindow frame) {
this.frame = frame;
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
((Timer) e.getSource()).stop();
}
}
#SuppressWarnings("serial")
class TranslucentPane extends JPanel {
private float composite;
public TranslucentPane(String s, float composite, float points) {
this.composite = composite;
JLabel label = new JLabel(s);
label.setFont(label.getFont().deriveFont(Font.BOLD, points));
add(label);
setOpaque(false); // this breaks a rule
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(composite));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose(); // dispose of any graphics we create
}
}
Code updated.
The main code has been moved to a public static method, since this appears to be code to display a message to the user and not to share state with any other code, similar to a JOptionPane message, so I'm making it behave like a JOptionPane.
Timer's ActionListener moved out of constructor for cleanliness.
Added parameters for alpha composite, display time, and message font point size.
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