I'm trying to rotate one whole Ellipse2D object based on user key input. If the user presses the right key, rotate right and left key means rotate left. The rotAngle is set to 25. I made a separate drawRotEllipse because otherwise it would have always drawn the original one. I think my confusion is happening with the Graphics and Shapes Objects. Tried the AffineTransform business but that didn't work out either. I just want it to rotate about the center. Thanks for any help!
class Canvas extends JPanel implements java.io.Serializable{
int x1 = (int) (this.getWidth()/2)+100;
int y1 = (int) (this.getHeight()/2)+20;
int x2 = (int) this.getWidth()+100;
int y2 = (int) this.getHeight()+200;
#Override
public void paintComponent(Graphics g){
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.RED);
drawEllipse(g);
}
public void drawEllipse (Graphics g){
Graphics2D g2d = (Graphics2D) g;
myShape = new Ellipse2D.Double(x1,y1,x2,y2);
g2d.draw(myShape);
this.repaint();
}
public void drawRotEllipse (Graphics g){
g2d.draw(myShape);
this.repaint();
}
}
private void jPanel1KeyPressed(java.awt.event.KeyEvent evt) {
if (evt.getKeyCode()==39){
g2d.rotate(Math.toDegrees(rotAngle));
myCanvas.drawRotEllipse(g2d);
}
else if (evt.getKeyCode()==37){
g2d.rotate(Math.toDegrees(-rotAngle));
myCanvas.drawRotEllipse(g2d);
}
}
if (evt.getKeyCode()==39)
Don't use magic numbers. People don't know that means by just looking at the code.
Instead use variable provided by the API:
if (evt.getKeyCode() == KeyEvent.VK_RIGHT)
You KeyEvent code should not do the actual painting. All the code should do is set the "degrees" property of your class. The setDegrees(...) method will then be responsible for invoking repaint(). Now whenever the component is repainted the shape will be painted at its current degrees of rotation.
Here is an example that uses a JSlider to change the rotation degrees of the class.
It rotates an image. You should be able to change the code rotation the image to just draw your shape:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation2 extends JPanel
{
BufferedImage image;
int degrees;
int point = 250;
public Rotation2(BufferedImage image)
{
this.image = image;
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
double radians = Math.toRadians( degrees );
g2.translate(point, point);
g2.rotate(radians);
g2.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2.drawImage(image, 0, 0, null);
g2.dispose();
g.setColor(Color.RED);
g.fillOval(point - 5, point - 5, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
// String path = "mong.jpg";
String path = "dukewavered.gif";
ClassLoader cl = Rotation2.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
final Rotation2 r = new Rotation2(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Related
First post in SO, hope I'm doing this right!
I'm trying to make a game in Java where a robot drives around and shines lines at nearby walls. Problem is, these lines stay onscreen, even when the robot moves, so it makes a cloud of lines that won't erase.
In the paintComponent(), I've tried g.fillRect(), but that doesn't erase any lines, just draws a rectangle behind that cloud. Every source I've seen so far seems to suggest things I've already done, unless I'm misunderstanding / overlooking something obvious...
'''
//from https://www.youtube.com/watch?v=p9Y-NBg8eto
/*
Other classes in this folder:
Robot.java Represents a robot, its location and angular orientation.
Obstacles.java Represents lines; the walls the robot should detect.
Sensor.java Represents the beams that shine from the robot to the walls.
//*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.ArrayList;
public class MyPanel extends JPanel implements ActionListener, KeyListener
{
Timer t = new Timer(5, this);
//OBSTACLES:
Obstacles obstacles=new Obstacles(0);
//ROBOT:
Robot robot = new Robot(obstacles);
//`````````````````````````````````````````````````````````
public MyPanel()
{
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
setVisible(true);
}
#Override
public void paintComponent(Graphics g)
{
g.dispose();
super.paintComponent(g);
//Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.RED);
g.fillRect(0, 0, 450, 450);
g.setColor(Color.BLACK);
//Graphics2D g2 = (Graphics2D) g;
robot.drawRobot(g);
drawBoundedBeams(g);
obstacles.drawObstacles(g);
drawSun(g);
}
#Override
public void actionPerformed(ActionEvent e)
{
repaint();
}
#Override
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if (code==KeyEvent.VK_UP)
robot.up();
if (code==KeyEvent.VK_DOWN)
robot.down();
if (code==KeyEvent.VK_LEFT)
robot.left();
if (code==KeyEvent.VK_RIGHT)
robot.right();
robot.updateSensor();
}
#Override public void keyTyped(KeyEvent e) {}
#Override public void keyReleased(KeyEvent e) {}
//```````````````````````````````````````````````````````````
public static void main(String [] args)
{
JFrame f = new JFrame();
MyPanel panel = new MyPanel();
f.add(panel);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
f.setVisible(true);
}
//Dummy lines. For some reason, these delete and move with the robot, no problem.
public void drawSun(Graphics g)
{
int x = (int) robot.x;
int y = (int) robot.y;
double t = robot.angle;
double xang = Math.cos(t);
double yang = Math.sin(t);
double east = (t + Math.PI/2) % (2 * Math.PI);
double eastx = Math.cos(east);
double easty = Math.sin(east);
g.drawLine(x, y, x+100, y);
g.drawLine(x, y, x-100, y);
g.drawLine(x, y, x, y+100);
g.drawLine(x, y, x, y-100);
g.drawLine(x, y, x+100, y+100);
g.drawLine(x, y, x+100, y-100);
g.drawLine(x, y, x-100, y+100);
g.drawLine(x, y, x-100, y-100);
g.drawLine(x, y, x+(int)(xang*100), y+(int)(yang*100));
g.drawLine(x, y, x-(int)(xang*100), y-(int)(yang*100));
g.drawLine(x, y, x+(int)(eastx*100), y+(int)(easty*100));
g.drawLine(x, y, x-(int)(eastx*100), y-(int)(easty*100));
}
//This was in Sensor.java, but I moved it here to try to fix it. (Didn't work.)
//THIS is what isn't getting deleted.
public void drawBoundedBeams(Graphics g) //Graphics2D g2
{
//Graphics2D g2 = (Graphics2D) g;
for (Integer[] beam : robot.sensor.boundedBeams)
{
g.drawLine(beam[0], beam[1], beam[2], beam[3]);
}
}
}
'''
~~~~~~ EDIT: I made a Minimal ~~~~~~
~~~~~~ Reproducible Example. ~~~~~~
MyPanel.java:
'''
/*
Classes in this (reprex) folder:
MyPanel.java displays things ****PROBLEM HERE(?)
Robot.java stores location and orientation
Sensor.java Shines beams outward ****PROBLEM HERE(?)
(I tried to keep the file structure consistent,
in case that was a factor for the issue.)
//*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.ArrayList;
public class MyPanel extends JPanel implements ActionListener, KeyListener
{
Timer t = new Timer(5, this);
Robot robot = new Robot();
//`````````````````````````````````````````````````````````
public MyPanel()
{
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
setVisible(true);
}
//********************************************
//********************************************
//********************************************
//**** Problem seems to be HERE. *************
//**** ~~~~~~~~~~~~~~~~~~~~~~~~ *************
//**** (See also: the method in *************
//**** Sensor.java; drawBeams()) *************
//********************************************
//********************************************
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
// And to smooth out the graphics, you can do the following
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
g2.fillRect(0, 0, 450, 450);
g2.setColor(Color.BLACK);
robot.sensor.drawBeams(g2);
g2.dispose();
}
#Override
public void actionPerformed(ActionEvent e)
{
repaint();
}
#Override
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if (code==KeyEvent.VK_UP)
robot.up();
if (code==KeyEvent.VK_DOWN)
robot.down();
if (code==KeyEvent.VK_LEFT)
robot.left();
if (code==KeyEvent.VK_RIGHT)
robot.right();
robot.updateSensor();
}
#Override public void keyTyped(KeyEvent e) {}
#Override public void keyReleased(KeyEvent e) {}
//```````````````````````````````````````````````````````````
public static void main(String [] args)
{
JFrame f = new JFrame();
MyPanel panel = new MyPanel();
f.add(panel);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
f.setVisible(true);
}
}
'''
Sensor.java:
'''
import java.lang.Math;
import java.util.ArrayList;
import java.awt.*;
class Sensor
{
private Robot robot;
public int numPieces;
public Integer range = 300;
public ArrayList<Double> offsets = new ArrayList<Double>(); //the angles of each beam
public ArrayList<Integer[]> beams = new ArrayList<Integer[]>(); //the beams that stretch out to the range public ArrayList<Integer[]> boundedBeams = new ArrayList<Integer[]>();
public Sensor(Robot robot)
{
this.robot=robot;
make12Sonars();
}
public void make12Sonars()
{
numPieces=12;
double offset = 0;
while (offset < 2*Math.PI)
{
offsets.add(offset);
offset += Math.PI / 6;
}
}
public void updateSensor()
{
makeBeams();
}
//```````````````````````````````````````````````````````
public void makeBeams() //Makes the maximum beams from the angles.
{
System.out.println("~~~MAKING BEAMS~~~");
for (Integer i=0; i<offsets.size(); i++)
{
System.out.println("\tat index "+i);
Double offset = offsets.get(i);
Double angle = (offset + robot.angle) % (2*Math.PI);
Integer[] beam = getSegment(robot.x, robot.y, angle, Double.valueOf(range));
beams.add(i, beam);
System.out.println("\t\tadded "+beam[0]+", "+beam[1]+", "+beam[2]+", "+beam[3]);
}
}
static public Integer[] getSegment(Double startX, Double startY, Double angle, Double radius)
{
Double x2 = radius * Math.cos(angle) + startX;
Double y2 = radius * Math.sin(angle) + startY;
Integer[] segment = {startX.intValue(), startY.intValue(), x2.intValue(), y2.intValue()};
return segment;
}
//********************************************
//********************************************
//********************************************
//**** Problem seems to be HERE. *************
//**** ~~~~~~~~~~~~~~~~~~~~~~~~ *************
//**** (The lines drawn here *************
//**** do not delete.) *************
//********************************************
//********************************************
public void drawBeams(Graphics g)
{
Integer x = (int) robot.x;
Integer y = (int) robot.y;
for (Integer[] beam : beams)
{
g.drawLine(beam[0], beam[1], beam[2], beam[3]);
}
}
}
'''
Robot.java:
'''
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.lang.Math;
class Robot
{
public double x=0, y=0; //center of the robot
public double velx=0, vely=0; //velocity of the robot
public double angle=0, speed=4; //radians, speed(before_direction)
public Sensor sensor;
public Robot()
{
sensor=new Sensor(this);
}
public void updateSensor() {sensor.updateSensor();}
//`````````````````````````````````````````````````````````````
//*
public void up() {x+=velx; y+=vely;}
public void down() {x-=velx; y-=vely;}
public void left()
{
angle -= 0.1;
angle = angle % (2*Math.PI);
velx = speed * Math.cos(angle);
vely = speed * Math.sin(angle);
}
public void right()
{
angle += 0.1;
angle = angle % (2*Math.PI);
velx = speed * Math.cos(angle);
vely = speed * Math.sin(angle);
} //*/
}
'''
You should not be disposing the default graphics context at the start of paintComponent(). The best thing to do is to make a copy via create and then later, dispose of that right before you return from paintComponent().
Try this as a your `paintComponent()` method.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
// And to smooth out the graphics, you can do the following
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
g2.fillRect(0, 0, 450, 450);
g2.setColor(Color.BLACK);
robot.drawRobot(g2);
drawBoundedBeams(g2);
obstacles.drawObstacles(g2);
drawSun(g2);
g2.dispose();
}
If this does not help solve your problem, please make a Minimal Reproducible Example that demonstrates the problem. It should not rely on anything that is not within the JDK API (i.e. third party classes, libraries, etc.)
My code rotates the image by 0.4 degrees every "update", the image rotates in range [-10,+10] continuously.
The problem is that the buffered image gets cut off at the edges when it rotates, seems like the rotation changes the size that the bufferedImage needs but the size never updates, any ideas how i can get it to work?
protected double rotation = 0;
private double rotDir = 0.4;
private BufferedImage getRotatedSprite(){
if(Math.abs(rotation)>10)
rotDir=rotDir*(-1);
rotation+=rotDir;
ImageIcon icon = new ImageIcon(bImage);
BufferedImage bImg = new BufferedImage(icon.getIconWidth(),
icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d= (Graphics2D)bImg.getGraphics();
g2d.rotate(Math.toRadians(rotation), icon.getIconWidth()/2, icon.getIconHeight()/2);
g2d.drawImage(bImage, 0, 0, null);
return bImg;
}
public void drawSprite(Graphics g) {
BufferedImage image = getRotatedSprite();
if(customWidth != -1 && customHeight != -1){
g.drawImage(image, (int)locX, (int)locY, customWidth, customHeight, this);
}else
g.drawImage(image, (int)locX, (int)locY, this);
}
seems like the rotation changes the size that the bufferedImage
Yes the size will change based on the angle of rotation.
You may find it easier to use the Rotated Icon. It does the rotation for you and recalculates the size (if necessary). There is no need to create new BufferedImages, you just set the degrees of rotation.
Simple example. Use the slilder bar to rotate the icon:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation3 extends JPanel
{
private Icon icon;
private RotatedIcon rotated;
private int degrees;
public Rotation3(Image image)
{
icon = new ImageIcon( image );
rotated = new RotatedIcon(icon, 0);
// rotated.setCircularIcon( true );
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// translate x/y so Icon rotated around a specific point (300, 300)
int x = 300 - (rotated.getIconWidth() / 2);
int y = 300 - (rotated.getIconHeight() / 2);
rotated.paintIcon(this, g, x, y);
g.setColor(Color.RED);
g.fillOval(295, 295, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
rotated.setDegrees(degrees);
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
// String path = "dukewavered.gif";
String path = "lunch75.jpg";
BufferedImage bi = ImageIO.read(Rotation3.class.getResourceAsStream(path));
final Rotation3 r = new Rotation3(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Hi guys I'm super new to Java; I've looked around and haven't been able to find an answer to this question. Any chance you could help me?
Here is an example of what I'm trying to achieve.
public class FrameWork extends JFrame implements MouseListener {
... //Irrelevant to the question code
public void mouseClicked(MouseEvent e){
int x = e.getX();
int y = e.getY();
if (x==1 && y==1){
// This is where and when I want to draw GFXDice
}
}}
Now the other class, all imports left out for readability.
public class Board extends JPanel{
Image GFXDice1;
public Board() {
ImageIcon Dice1;
Dice1 = new ImageIcon(this.getClass().getResource("GFX/Dice1"));
GFXDice1 = Dice1.getImage();
}
Now the graphics part
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(GFXDice, 100, 100, null);
}
Now for the question - I want to use the method paint from the Class Board in the Class FrameWork - But can't get it to work - any ideas ? I'm offering a bazillion units of good karma to anyone who has an idea.
The general way to do most Swing drawing is via passive graphics. This means:
Do the drawing itself in the paintComponent(Graphics g) method of a JPanel or JComponent.
In your MouseListener change the state of some of the fields of the class. In your mouseClicked method you are setting the state of some local variables, and I recommend that you instead make your x and y fields, not local.
Then when the mouse listener is done making changes, call repaint() on the JPanel.
Then in the paintComponent method, use those fields that were changed in the mouse listener to do your drawing.
Don't forget to call the super's paintComponent method in your paintComponent override.
Don't forget to read tutorials on Swing Graphics to get the fine points.
Edit
For example, please have a look at a small graphics program that I created for an answer to another recent question.
The drawing occurs in the main class, SpaceShip, which extends JPanel. I add an anonymous inner MouseAdapter class for my Mouse Listener, and inside of the MouseAdapter, I call a method called moveIt, passing in the MouseEvent object.
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
moveIt(evt);
count = count + 1;
}
#Override
public void mouseDragged(MouseEvent evt) {
moveIt(evt);
}
};
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
All moveIt(MouseEvent evt) does is to change the state of two fields, myX and myY, and then calls repaint() on the current class:
public void moveIt(MouseEvent evt) {
myY = evt.getY() - sprite.getHeight() / 2;
myX = evt.getX() - sprite.getWidth() / 2;
repaint();
}
And then in the class's paintComponent method, I first call the super's paintComponent to allow it to erase any previous old out of date images, then I paint a background image, background, then I draw a sprite that uses the myX and myY variables to tell it where to draw, then I draw some yellow rectangles at locations that are determined by the JPanel's size:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
font1 = new Font("Serif", Font.BOLD, 36);
g.drawImage(background, 0, 0, this);
g.drawImage(sprite, myX, myY, this);
g.setColor(Color.yellow);
int rectCount = 10;
int height = getHeight() / rectCount;
int width = 272;
int x = getWidth() - width;
for (int i = 0; i < rectCount; i++) {
int y = i * height;
g.drawRect(x, y, width, height);
}
g.setFont(font1);
g.drawString(Integer.toString(count), 500, 100);
}
The whole thing looks like this:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.IOException;
import java.net.URL;
import java.lang.String;
import java.awt.Font;
#SuppressWarnings("serial")
public class SpaceShip extends JPanel {
private static final String BACKGROUND_PATH = "http://www.thatsreallypossible.com/"
+ "wp-content/uploads/2012/12/Space-Colonialisation.jpg";
private static final String SPRITE_PATH = "http://www.pd4pic.com/"
+ "images250_/ufo-flying-saucer-spacecraft-spaceship-alien.png";
private Font font1;
int myX = 100;
int myY = 400;
int count = 0;
private BufferedImage background;
private BufferedImage sprite;
public SpaceShip() throws IOException {
URL backgroundUrl = new URL(BACKGROUND_PATH);
URL spriteUrl = new URL(SPRITE_PATH);
background = ImageIO.read(backgroundUrl);
sprite = ImageIO.read(spriteUrl);
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
moveIt(evt);
count = count + 1;
}
#Override
public void mouseDragged(MouseEvent evt) {
moveIt(evt);
}
};
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
public Dimension getPreferredSize() {
if (background != null) {
return new Dimension(background.getWidth(), background.getHeight());
}
return super.getPreferredSize();
}
public void moveIt(MouseEvent evt) {
myY = evt.getY() - sprite.getHeight() / 2;
myX = evt.getX() - sprite.getWidth() / 2;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
font1 = new Font("Serif", Font.BOLD, 36);
g.drawImage(background, 0, 0, this);
g.drawImage(sprite, myX, myY, this);
g.setColor(Color.yellow);
int rectCount = 10;
int height = getHeight() / rectCount;
int width = 272;
int x = getWidth() - width;
for (int i = 0; i < rectCount; i++) {
int y = i * height;
g.drawRect(x, y, width, height);
}
g.setFont(font1);
g.drawString(Integer.toString(count), 500, 100);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Basic Game");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
SpaceShip ex;
try {
ex = new SpaceShip();
frame.getContentPane().add(ex);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
ex.requestFocus();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have this simple paint code that should draw but instead it moves the oval around the panel.
When I remove super.paintComponent(g) line the program works it paints and not just move the oval, but I keep reading that we should not remove this line, so what can I do to leave the line in but still get the desired results?
class OraclePaint extends JFrame {
public static void main(String[] args) {
OraclePaint ss = new OraclePaint();
ss.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ss.add(new MyPanel());
ss.setSize(250, 200);
ss.setVisible(true);
}
}
class MyPanel extends JPanel {
private int x = -10, y = -10;
public MyPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent event) {
x = event.getX();
y = event.getY();
repaint();
}
}); // end call to addMouseMotionListener
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 22, 22);
}
}
Based on the description, I assume that you want something like "a simple paint program".
It is correct to invoke super.paintComponent(g) as the first line of an overridden paintComponent. And it is true that this erases the background (that is, everything that was painted before will be deleted).
In Swing, everything that you want to paint has to be painted in the paintComponent method (or in any method that is called from there, and receives the same Graphics object).
If you want to "save" everything that you have painted, you have to paint everything into an image (that is, into a BufferedImage), and paint this image in your paintComponent method.
There are some other issues with the code, but without changing too much of the remaining code, this could roughly (!) be achieved like this:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
class OraclePaint extends JFrame {
public static void main(String[] args) {
OraclePaint ss = new OraclePaint();
ss.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ss.add(new MyPanel());
ss.setSize(250, 200);
ss.setVisible(true);
}
}
class MyPanel extends JPanel {
private BufferedImage image = null;
public MyPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent event) {
if (image != null) {
// Paint into the image
Graphics g = image.getGraphics();
g.setColor(Color.BLACK);
g.fillOval(event.getX(), event.getY(), 22, 22);
g.dispose();
repaint();
}
}
}); // end call to addMouseMotionListener
}
// Make sure that the image is not 'null' and that
// it has the same size as this panel
private void validateImage()
{
if (image == null)
{
image = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
}
if (image.getWidth() != getWidth() || image.getHeight() != getHeight())
{
BufferedImage newImage = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
image = newImage;
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
validateImage();
g.drawImage(image, 0, 0, null);
}
}
change your MyPanel to this:
class MyPanel extends JPanel
{
private int x2 = 0, y2 = 0;
private int x1 = 0, y1 = 0;
public MyPanel()
{
addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged( MouseEvent event )
{
x2 = event.getX();
y2 = event.getY();
repaint();
}
}
); // end call to addMouseMotionListener
addMouseListener(new MouseListener() {
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
}
});
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x1, y1, x2, y2);
}
}
I am trying to create a button which looks as shown below and continuously fades in and fades out .It looks like :-
Now i have done till the looks with gradient paint but what should i do to make the button text appear.Inspite of calling 'super(s)' it doesn't appear as i have painted it with GradientPaint.What should i do make the text appear over paint.My code is shown below :-
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Fader extends JFrame{
Fader()
{
super("A fading button");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setSize(400,400);
add(new CustomButton("Submit"));
setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable(){public void run(){new Fader();}});
}
}
class CustomButton extends JButton
{
public CustomButton(String s) {
super(s);
// TODO Auto-generated constructor stub
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g.create();
GradientPaint gp=new GradientPaint(0, 0, Color.RED, 200, 100, Color.YELLOW);
g2.setPaint(gp);
g2.fillRect(0, 0, getWidth(), getHeight());
}
public Dimension getPreferredSize()
{
return new Dimension(200,100);
}
}
Secondly,an advice to implement the fade in and out effect is also requested.
You can use this option, that paints a transparent color gradient on a component:
#Override
public void paintComponent(Graphics g){
super.paintComponent( g );
Graphics2D g2=(Graphics2D)g.create();
int h = getHeight();
int w = getWidth();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .5f));
g2.setPaint(new GradientPaint(0, 0, Color.yellow, 0, h, Color.red));
g2.fillRect(0, 0, w, h);
g2.dispose();
}
Other pretty good example with fading in (as requested). I used RadialGradientPaint. You can play with AlphaComposite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .4f));
where 4f represent transparent level 40%
#Override
public void paintComponent(Graphics g){
super.paintComponent( g );
Graphics2D g2=(Graphics2D)g.create();
int h = getHeight();
int w = getWidth();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f));
Point2D center = new Point2D.Float(100, 50);
float radius = 150;
float[] dist = {0.0f, 1.0f};
Color[] colors = {Color.yellow, Color.red};
RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, colors);
g2.setPaint(p);
g2.fillRect(0, 0, w, h);
g2.dispose();
}
Finally we can play with alpha dynamically. Her is the full code. I created simple thread that change me alpha from 0 to 9 and vise versa. Here we go:
public class Fader extends JFrame{
private static final long serialVersionUID = 1L;
static JButton button;
public static float mTransparent = .0f;
Fader(){
super("A fading button");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setSize(400,400);
JButton button = new CustomButton("Submit");
add(button);
setVisible(true);
Blink blink = new Blink(this);
blink.start();
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){public void run(){new Fader();}});
}
public static float getTransparentLevel() {
return mTransparent;
}
public void setTransparentLevel(float newVal) {
mTransparent = newVal;
if(button != null){
button.repaint();
}
repaint();
}
}
class Blink extends Thread{
Fader fader;
public Blink(Fader fader) {
this.fader = fader;
}
#Override
public void run(){
while(true){
if(Fader.getTransparentLevel() == 0.0f){
//increase to 1f
for(int i=1; i<10; i++){
fader.setTransparentLevel((float)i/10);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
else if(Fader.getTransparentLevel() == 0.9f){
//increase to 1f
for(int i=10; i>=0; i--){
fader.setTransparentLevel((float)i/10);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class CustomButton extends JButton {
private static final long serialVersionUID = 1L;
public CustomButton(String s) {
super(s);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent( g );
Graphics2D g2=(Graphics2D)g.create();
int h = getHeight();
int w = getWidth();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, Fader.getTransparentLevel()));
Point2D center = new Point2D.Float(100, 50);
float radius = 150;
float[] dist = {0.0f, 1.0f};
Color[] colors = {Color.yellow, Color.red};
RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, colors);
g2.setPaint(p);
g2.fillRect(0, 0, w, h);
g2.dispose();
}
public Dimension getPreferredSize(){
return new Dimension(200,100);
}
}
It blinks with sleep 300 ms from .0 to .9 of transparent and back from .9 to .0:
-->
Once you override the paintComponent() method, you are on your own with drawing the button. So, you will have to draw the text yourself. Something like this will help:
g2.setColor(Color.GREEN);
g2.drawString(getText(), 0, 10);
The above code must be added after the fillRect method. However, you will have to use FontMetrics in order to position the text according to the text alignment preferences.
To fadeIn and fadeOut you will need to implement your own Animation Sequencer that runs in a different thread, that will constantly vary the alpha value with a TimerTask. Once the value of alpha reaches 0, it should be incremented back to 100%.
Also check out the book by Romain Guy: Filthy Rich Java Clients