Repaint() doesn't clear the frame - java

public class Graphics2DTest extends JPanel implements ActionListener{
private Timer time = new Timer(5,(ActionListener) this);
int x = 0,y = 0;
public void paintComponent(Graphics g){
Graphics2D gui = (Graphics2D) g;
Rectangle2D rectangle = new Rectangle2D.Double(x,y,100,150);
gui.setPaint(Color.GREEN);
gui.fill(rectangle);
time.start();
}
public void actionPerformed(ActionEvent arg0) {
x++;
y++;
repaint();
}
}
The problem is repaint() is supposed to clear the frame and draw the rectangle in the position, but the previously painted rectangle remains. So, how to do it? Please explain your answers.

Have you tried calling super.paintComponent(g) in your paintComponent method? This will clear prior images drawn in your JPanel:
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D gui = (Graphics2D) g;
Rectangle2D rectangle = new Rectangle2D.Double(x,y,100,150);
gui.setPaint(Color.GREEN);
gui.fill(rectangle);
//time.start();
}
Also, don't start a timer or do any program logic within the paintComponent method. First of all you cannot absolutely control when or if the method will be called, and secondly, this method must be concerned only with painting and nothing else, and needs to be as fast as possible.
For instance:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class Graphics2DTest extends JPanel implements ActionListener {
private Timer time = new Timer(5, (ActionListener) this);
int x = 0, y = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gui = (Graphics2D) g;
Rectangle2D rectangle = new Rectangle2D.Double(x, y, 100, 150);
gui.setPaint(Color.GREEN);
gui.fill(rectangle);
//time.start();
}
public void actionPerformed(ActionEvent arg0) {
x++;
y++;
repaint();
}
public Graphics2DTest() {
setPreferredSize(new Dimension(700, 500));
time.start();
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Graphics2DTest");
frame.getContentPane().add(new Graphics2DTest());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}

You need to repaint the background each time as well. Add code to paint the background before you paint the rectangle.

You need to clear the background first.
A resource is this:
http://java.sun.com/products/jfc/tsc/articles/painting/

Related

Buttons not visible until mouseover

I created a frame and panel (for Graphics) and add buttons to the panel. However, when I run my program buttons are not visible until I hover over them. Maybe it is something wrong with graphics methods.
How the problem can be solved?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main{
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(600,500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
Panel panel = new Panel();
f.add(panel);
f.setVisible(true);
}
}
class Panel extends JPanel implements ActionListener{
int[] x = {200,400,300,200};
int[] y = {100,100,200,100};
JButton fillRed;
JButton fillBlack;
JButton cancel;
Panel(){
this.setLayout(null);
fillRed = new JButton("Red");
fillRed.setBounds(50, 400, 100, 50);
fillRed.addActionListener(this);
this.add(fillRed);
fillBlack = new JButton("Black");
fillBlack.setBounds(250, 400, 100, 50);
fillBlack.addActionListener(this);
this.add(fillBlack);
cancel = new JButton("Cancel");
cancel.setBounds(450,400,100,50);
cancel.addActionListener(this);
this.add(cancel);
}
public void paint(Graphics g) {
super.paintComponent(g);
g.drawPolygon(x,y,4);
}
public void fillRed(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillPolygon(x,y,4);
}
public void fillBlack(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillPolygon(x,y,4);
}
public void cancel(Graphics g) {
super.paintComponent(g);
g.drawPolygon(x,y,4);
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==fillRed) {
fillRed(getGraphics());
}
if(e.getSource()==fillBlack) {
fillBlack(getGraphics());
}
if(e.getSource()==cancel) {
cancel(getGraphics());
}
}
}
Your painting code is mostly wrong. For example:
public void paint(Graphics g) {
super.paintComponent(g);
g.drawPolygon(x,y,4);
}
If you need to override paint() then the first statement should be super.paint(g).
However, you should NOT override paint. For custom painting you override paintComponent(...) and then invoke super.paintComponent(g). Read the Swing tutorial on Custom Painting for more information and working examples.
public void fillBlack(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillPolygon(x,y,4);
}
Never invoke paintComponent(...) directly. If you need to change a property of a component then you invoke repaint() and Swing will invoke the painting methods.
if(e.getSource()==fillRed) {
fillRed(getGraphics());
}
Don't invoke getGraphics() on a Swing component. Painting is done by setting properties of your class and then you invoke repaint(). If you need to paint multiple objects then you need to keep track of each object you want to paint and then in the painting method you paint every object. Check out Custom Painting Approaches for example of how this can be done.

repaint causes component overflow

I hope that I used the question function correctly this time. I have been confused by a question from yesterday to now. I used Google search to ask my java teacher and did not solve my problem.
When I use repaint, the child components in the shaped JPanel will exceed their display area. As in the following figures,
This is the effect I want
But when I use repaint somethings changes.
The button doesn’t seem right at first.
But sometimes the button will return to normal
these are my code. I use repaint because the information I checked tells me that I can use it. Repaint to achieve animation effects.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
class GPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.clip(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), getWidth(), getHeight()));
g2d.setPaint(Color.BLUE);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
public class MainComponentOverflow {
public static void main(String[] args) {
JFrame frame = new JFrame();
// This is a panel with a shape
GPanel panel = new GPanel();
// This one is the effect I am looking for, the rectangle is displayed in the Panel.
//panel.add(new Normal());
// The following two will have problems, the rectangle will be displayed outside the Panel
//panel.add(new Problem1());
panel.add(new Problem2());
//panel.add(new JButton("This will also cause problems, but it may also display properly when I resize the window."));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
class Normal extends JPanel {
public Normal() {
setPreferredSize(new Dimension(500, 500));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
class Problem1 extends JPanel implements ActionListener {
public Problem1() {
Timer timer = new Timer(16, this);
timer.start();
setPreferredSize(new Dimension(500, 500));
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
class Problem2 extends JPanel implements ActionListener {
public Problem2() {
Timer timer = new Timer(16, this);
timer.start();
setPreferredSize(new Dimension(500, 500));
}
#Override
public void actionPerformed(ActionEvent e) {
setBackground(new Color((float) Math.random(), (float)Math.random(), (float)Math.random()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
When the frame is painted first, the clip will be set in GPanel, and then the children will be painted in Problem1 with the same clip, so it will work.
However, when you repaint Problem1, GPanel will not be repainted first, so the clip isn’t set, and there is no clip to restrict Problem1.
If instead of repainting Problem1 you repaint the parent, GPanel, it will resolve your problem.
Another solution would be to put the clip in Problem1 too.
Note that you can replace your RoundRect2D with an Ellipse2D, as you use it to paint an ellipse.

How to repaint a java.awt.Window?

why is my java.awt.Window not repainting after I called the repaint() method?
public class Counter extends Window implements ActionListener {
private static final long serialVersionUID = 1L;
private Timer timer;
private int time;
public Counter() {
super(null);
setAlwaysOnTop(true);
setBounds(getGraphicsConfiguration().getBounds());
setBackground(new Color(0, true));
setVisible(true);
timer = new Timer(1000, this);
timer.start();
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.clearRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawString(String.valueOf(time), getWidth()/2, getHeight()/2);
}
#Override
public void update(Graphics g) {
super.update(g);
}
#Override
public void actionPerformed(ActionEvent e) {
time++;
repaint();
}
As you can see i created a timer with a delay of 1 second. After that i call repaint() to draw the counter's number on the screen. But it only draws a zero on my screen and stops drawing then (the zero stays on screen). First i thought that the paint method is only called once, but i tested a System.out.prinln() and prooved that the paint method is executed every second so it should actually repaint the window... So i don't know where i made a mistake.
And yes it is my intention to use the awt.Window and not a JFrame or Frame etc..
I finally got to run the code on Windows 7, and I could replicate the issue. For some reason, paint isn't being called; why, I don't know. Because I wouldn't do it this way, I've never had that issue.
Instead, I'd start by having the counter class extend from something JPanel or JComponent (just remember to make JPanel transparent) and then add it to a JWindow, something like this:
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 javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
public class Counter extends JPanel implements ActionListener {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JWindow window = new JWindow();
window.add(new Counter());
window.pack();
window.setLocationRelativeTo(null);
window.setBackground(new Color(0, 0, 0, 0));
window.setVisible(true);
}
});
}
private static final long serialVersionUID = 1L;
private Timer timer;
private int time;
public Counter() {
setOpaque(false);
timer = new Timer(1000, this);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
System.out.println(time);
g.clearRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawString(String.valueOf(time), getWidth() / 2, getHeight() / 2);
}
#Override
public void actionPerformed(ActionEvent e) {
time++;
System.out.println("..." + time);
repaint();
}
}

AWT graphics, object disappears briefly

I am trying to learn how to make a graphics program, but some of the methods in java AWT are giving me unexpected results.
I have made a window, and I place a rectangle and that works. I want another figure, a circle, to appear after 1 second. I have tried the wait(x) method, which just places the circle immediately, and now I have tried the Thread.sleep(x) method, which does work, however I get the following behaviour:
After one second, the circle is displayed on the screen, but after a split second it disappears again, and another split second later it reappears and stays on the screen. I don't want it to temporarily disappear. What am I doing wrong?
import java.awt.*;
class Example extends Canvas{
public static void main(String[] args){
Example graphicProgram = new Example();
Frame graphics = new Frame();
graphics.setSize(300, 300);
graphics.add(graphicProgram);
graphics.setVisible(true);
}
public Example(){
setSize(200, 200);
setBackground(Color.white);
}
public void paint(Graphics g){
g.fillRect(20, 150, 100, 100);
try{
Thread.sleep(1000);
} catch (Exception ex){
}
g.fillOval(150, 20, 100, 100);
}
}
Never call Thread.sleep from within a paint type of method. Doing this will make your GUI completely unresponsive.
Yes, do call the super painting method from within your painting method (as per muhammad's answer).
You should not call Thread.sleep(...) from the event thread either as this too will freeze your application.
You should skip doing AWT and move to Swing.
When you do so, do your drawing in the paintComponent(Graphics g) method of a JComponent or JPanel object.
Call the super's paintComponent(g) within your paintComponent method override.
Use a Swing Timer to do any delay or animation.
e.g.,
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class DrawFoo extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Stroke BASIC_STROKE = new BasicStroke(3f);
private static final Color RECT_COLOR = Color.blue;
private static final Color OVAL_COLOR = Color.red;
private boolean drawCircle = false;
private int rectX = 20;
private int rectY = 150;
private int rectWidth = 100;
public DrawFoo() {
int delay = 1000;
Timer timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
drawCircle = true;
repaint();
}
});
timer.setRepeats(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(BASIC_STROKE);
g2.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, rectWidth, rectWidth);
if (drawCircle) {
g2.setColor(OVAL_COLOR);
g.fillOval(rectY, rectX, rectWidth, rectWidth);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawFoo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
put this line as the first statment in your paint method super.paint(g);
it will be good to place also Graphics2D g2 = (Graphics2D)g; after above statment to use the improved performance and extra methods offered by Graphics2D

Timer move an object of Graphics2D over an image in JFrame? (Sunrise program example)

I'm trying to write a program to design a sunrise animation by using Timer and JFrame and JComponent. The Object of Graphics2D is the sun which is going to move over JFrame. My problem is that I'm not sure where to place the Timer and move the Graphicc2D! Here is what I have done so far to place an image in JFrame and then place the sun on that image. Please tell me where I can manage to move the sun. where should I define Timer class? In JFrame or JComponent or main class?
public class Main(){
public static void main(String[] args){
myFrame frame = new myFrame();
}
}
class myFrame extends JFrame
{
public myFrame()
{
Draw component = new Draw();
add(component);
}
}
class Draw extends JComponent
{
public Draw()
{
//Read the image here
//set the newImage
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(newImage, 0, 0, null);
g2.fill(new Ellipse2D.Double(x,y,20,20));
//For the sunrise I need to change x,y during the Timer class!!
}
}
This should do:
int x, y;
Timer timer = new Timer(50, new ActionListener(){
public void actionPerformed(ActionEvent evt){
// update x and y
repaint();
}
});
Don't forget to start the timer, (it's preferred to do so, in the constructor).

Categories

Resources