i have this code:
public class Intersect extends JFrame {
private boolean collision = false;
public Intersect() {
add(new JPanel() {
#Override
protected void paintComponent(Graphics g) {
Shape oval = new Ellipse2D.Double(50, 50, 200, 200);
Shape rect = new Rectangle2D.Double(200, 200, 200, 200);
Graphics2D g2 = (Graphics2D) g;
g2.draw(oval);
g2.draw(rect);
if(oval.intersects(rect.getBounds())) {
System.out.println("contact");
collision = true;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
});
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
Intersect i = new Intersect();
i.setVisible(true);
if(i.collision == true)
System.out.println("boom");
else System.out.println("no boom");
}
}
result in console:"
no boom
contact
contact
contact"
program keep false value in variable collision for all the time, but why it print "contact" if it dont change variable collision to true? (in condition if(oval.intersects(rect.getBounds())))
Painting happens asynchronously in response to requests from the operating system to paint the window. It doesn't happen immediately when you call setVisible(true);.
So it does set the collision variable to true. It just hasn't happened yet at the time the code in main runs. This is why "contact" is printed after "no boom".
Edit: The way I'd suggest fixing it is to separate the collision logic from the painting code. E.g., declare the Shapes as fields on the frame, so they are available outside the paint method:
class Intersect extends JFrame {
private Shape oval = new Ellipse2D.Double(50, 50, 200, 200);
private Shape rect = new Rectangle2D.Double(200, 200, 200, 200);
The panel's painting method becomes simply:
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.draw(oval);
g2.draw(rect);
}
Then remove the collision variable and make it a method so you can call it at any time:
boolean collision() {
return oval.intersects(rect.getBounds());
}
public static void main(String[] args) {
Intersect i = new Intersect();
i.setVisible(true);
if (i.collision())
System.out.println("boom");
else System.out.println("no boom");
}
Note: There is another (potential) problem with this code. All GUI-related activity is supposed to happen on a dedicated thread, the event dispatch thread. The main method should switch to the event dispatch thread before creating the GUI. To do this, change the beginning of main to this:
public static void main(final String[] args) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
main(args);
}
});
return;
}
Intersect i = new Intersect();
...
That will re-call main on the GUI thread.
Related
I'm trying to draw a shape multiple times inside a JPanel to mimic an animation (a moving shape across it). The problem is that the shape is being redrawn and thus appearing on the screen multiple times on different places, when all i pretend is that only one shape is visible at a time when it's being redrawn.
The method super.paintComponent() should be responsible for repainting JPanel's background and thus, only one shape should be visible when the redrawing is being performed.
I have the following code (it has been reduced/simplified for the sake of simplicity and better understanding):
public class Animated_Shape_Test extends JFrame
{
public static void main(String args[]) throws IOException
{
new Animated_Shape_Test();
}
public Animated_Shape_Test() throws IOException
{
this.setSize(500, 500);
this.setPreferredSize(new Dimension(500, 500));
this.setLocation(new Point(430, 150));
this.setTitle("Database Launcher v1.0");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setVisible(true);
DBPanel panel = new DBPanel();
getContentPane().add(panel, BorderLayout.CENTER);
}
}
final class DBPanel extends JPanel implements Runnable
{
int musicShapePosX = 85;
int musicShapePosY = 100;
int SEGMENT_SHAPE_LENGTH = 50;
int SHAPE_HEIGHT = 10;
float SHAPE_SPEED = 7.5f;
CustomShapeButton musicShapeButton = new CustomShapeButton(musicShapePosX, musicShapePosY, SEGMENT_SHAPE_LENGTH, SHAPE_HEIGHT);
private ArrayList<Shape> shapes = null;
protected DBPanel() throws IOException
{
shapes = new ArrayList();
shapes.add(musicShapeButton);
this.setOpaque(true);
this.setFocusable(true);
startThread();
}
public void startThread()
{
Thread t = new Thread(this);
t.start();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground().darker());
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.BLACK);
g2.draw(musicShapeButton);
}
public void delay(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
}
}
#Override
public void run()
{
while (true)
{
delay(35);
animateButtonShapeMusic();
repaint();
}
}
public void animateButtonShapeMusic()
{
if (musicShapePosY < 228)
{
musicShapePosY = (int)(musicShapePosY + SHAPE_SPEED);
musicShapeButton.drawShape(musicShapePosX, musicShapePosY, SEGMENT_SHAPE_LENGTH, SHAPE_HEIGHT);
}
}
}
I'm getting several shapes being redrawn across the screen (animation).
I expect a single shape being redrawn across the screen (animation).
Thank you in advance.
I want to indicate status of a station by marking color over a region. Graphics2D class is used to draw color. It has to be updated continuously. I am using timer but it is not working. Any help is appreciated.
import javax.swing.*;
import java.awt.*;
import redis.clients.jedis.Jedis;
public class Station1 {
public Station1(){
Gradient gradient = new Gradient();
JFrame f = new JFrame("Input Carousel");
f.setLayout(new BorderLayout());
JLabel label = new JLabel();
ImageIcon icon = new ImageIcon(getClass().getResource("images/input carousel.jpg"));
label.setIcon(icon);
gradient.add(label);
f.add(gradient);
f.pack();
f.setResizable(false);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new Station1();
}
});
}
class Gradient extends JPanel{
public Graphics2D g2D ;
#Override
public void paintComponent(Graphics g){
g2D = (Graphics2D)g;
AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
g2D.setComposite(alphaComposite);
new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
try{
Jedis jedis = new Jedis("localhost");
if(jedis.get("b1").equals("1"))
{
g2D.setColor(Color.GREEN);
g2D.fillRect(208, 172, 47, 75);
}
else if(jedis.get("b1").equals("e"))
{
g2D.setColor(Color.RED);
g2D.fillRect(208, 172, 47, 75);
}
}
catch(Exception e)
{
}
}
}).start();
}
}
}
If I run the code without timer it is working. If I use timer, it will not draw any color.
Please suggest me solution for this problem.
You've several glaring issues with that code:
Starting a Timer within a painting method, a method that often gets called many times, most of which you have no control over
Calling what looks like potentially blocking code within a painting method (and within the Swing event thread). This may render your code completely useless as this can potentially freeze the gui
Suggestions:
Create the Timer and start it once and not within any painting method. Perhaps do this within a class's constructor
The timer should change fields of the class and call repaint
Your painting method should then use the state of these fields to decide what to paint and where
Don't forget to call the super.paintComponent(g); in your override, usually on its first line.
If creating Jedis means creating a long-running bit of code, do this within a background thread such as a SwingWorker
A painting method is for painting and painting only, and your code should respect this.
For example, please have a look at the code below. Note that I do not have access to your Jedis class (nor why you're using it), and so created a "mock" class. Also, I do not have access to your image, and so used a publicly available image for this demo program. I also sped up your timer.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
// import redis.clients.jedis.Jedis;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class Station1 {
private static final String IMG_PATH = "https://upload.wikimedia.org/wikipedia/"
+ "commons/thumb/f/f4/LINCOLN%2C_Abraham-President_%28BEP_engraved_portrait%29.jpg"
+ "/800px-LINCOLN%2C_Abraham-President_%28BEP_engraved_portrait%29.jpg";
public Station1() {
Gradient gradient = new Gradient();
JFrame f = new JFrame("Input Carousel");
f.setLayout(new BorderLayout());
JLabel label = new JLabel();
// ImageIcon icon = new ImageIcon(getClass().getResource("images/input carousel.jpg"));
BufferedImage img = null;
try {
URL imgUrl = new URL(IMG_PATH);
img = ImageIO.read(imgUrl);
} catch (IOException e) {
e.printStackTrace();
}
Icon icon = new ImageIcon(img);
label.setIcon(icon);
gradient.add(label);
f.add(gradient);
f.pack();
f.setResizable(false);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Station1();
}
});
}
#SuppressWarnings("serial")
class Gradient extends JPanel {
private JedisMock jedisMock = new JedisMock("localhost");
private String jedisValue = "";
public Gradient() {
int timerDelay = 200;
new Timer(timerDelay, new TimerListener()).start();
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// may need to wrap this within a try/catch
jedisValue = jedisMock.get("b1");
repaint();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
0.5f);
g2D.setComposite(alphaComposite);
if (jedisValue.equals("1")) {
g2D.setColor(Color.GREEN);
g2D.fillRect(208, 172, 47, 75);
} else if (jedisValue.equals("e")) {
g2D.setColor(Color.RED);
g2D.fillRect(208, 172, 47, 75);
}
}
}
}
public class JedisMock {
private String host;
public JedisMock(String host) {
this.host = host;
}
public String getHost() {
return host;
}
// method to mock your method
public String get(String text) {
double randomValue = Math.random();
if (randomValue < 0.333) {
return "1";
} else if (randomValue < 0.667) {
return "e";
} else {
return "";
}
}
}
Here is my problem :
I have made a program that draws squares at random locations, its a tad crude but it works.
However the problem is that it will not repaint properly, I don't know where but somewhere in the code I made a mistake.
This causes the following to happen : I tell the application to draw 5 squares it does so but then when I tell it to draw 6 it will draw the previous 5 + 6.
The code is listed below in two parts RandomSquares and DrawField :
public class RandomSquares extends JPanel {
private static JFrame frame = new JFrame("Random Squares");
private static DrawField f;
private static JButton button = new JButton("Make squares");
private static final JTextField field = new JTextField(10);
private static int amount = 0;
private static void prepareFrame() {
//knoppen
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println(amount);
amount = Integer.parseInt(field.getText());
f = new DrawField(amount);
frame.add(f, BorderLayout.CENTER);
frame.repaint();
}
});
frame.add(button, BorderLayout.NORTH);
frame.add(field, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
Listener l = new Listener();
frame.addKeyListener(l);
frame.setSize(640, 480);
}
public static class Listener implements KeyListener {
#Override
public void keyTyped(KeyEvent ke) {
//unused
}
#Override
public void keyPressed(KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_R) {
System.out.println("woot!");
}
}
#Override
public void keyReleased(KeyEvent ke) {
//unused
}
}
public static void run() {
f = new DrawField(amount);
prepareFrame();
frame.setVisible(true);
}
}
public class DrawField extends JComponent {
private int amount;
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public DrawField(int amount) {
this.amount = amount;
this.setSize(540, 380);
this.setBackground(Color.GREEN);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Random r = new Random();
for (int i = 0; i < amount; i++) {
g.fillRect(r.nextInt(getWidth()), r.nextInt(getHeight()),
20, 20);
}
}
}
Painting methods should only be used for painting, not setting properties of your class.
g.fillRect(r.nextInt(getWidth()), r.nextInt(getHeight()), 20, 20);
For example if you resize the frame a whole new set of rectangles will be painted at new random locations.
When you invoke super.paintComponent(), the old drawing will be lost and new random rectangle will be created.
Instead your painting code should be based on properties of the class. That is once you create the objects they should be fixed so a repaint of the component does not change the painting, unless you change the properties.
See Custom Painting Approaches for examples of how to painting with a random number of objects by:
keeping a List of objects to paint
add objects to a BufferedImage and then just paint the image.
In your case you would invoke the addRectangles(...) method for the specified number of rectangle you want to paint. Then the painting code will do the rest.
Edit:
To answer your basic question. In general you need to invoke super.paintComponent() to clear the background of a component before doing the custom painting of the component.
The problem is that you are extending JComponent, which doesn't not have any default painting code, so the background doesn't get cleared. Two solutions:
Extend JPanel instead (JPanel does clear the background).
Add custom painting code to your class to clear the background:
Something like:
g.setColor( getBackground() );
f.fillRect(0, 0, getWidth(), getHeight());
// paint rectangle here
I tell the application to draw 5 squares it does so but then when I tell it to draw 6 it will draw the previous 5 + 6.
The Component is not being cleared of any previous painting calls - be sure to always call the parent painting method to clear any previous painting. For example:
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
//custom painting here.
}
so I am trying to make a simple program where you click on the screen and it creates a block that falls and collides with a larger block beneath and sticks to it. Kind of like a simple collision program. The problem is when I create one block it deletes the block previously. I made an array, but it still does this. Do any of you know what Im doing wrong? Im sure its a simple fix.
public class Screen extends JPanel implements Runnable {
public static JLabel statusbar; //displays a status bar showing what mouse movements are taking place
private Image cat; //image of the cat
public int xCoord ; //get the coordinates of the mouse pressed
public int yCoord ;
public int xCreate;
public int yCreate;
public Rectangle Ground;
public Rectangle Block;
public boolean isClicked = false;
public int clickCount = 0;
Rectangle blocks[] = new Rectangle[10];
int blocknum = 0;
public Screen(Frame frame) {
loadPic(); //calls the loadPic method above
Handlerclass handler = new Handlerclass(); //creates a new class to use the mouse motion listener
System.out.println("mouse works!");
addMouseListener(handler);
addMouseMotionListener(handler);
statusbar = new JLabel("default");
add(statusbar);
}
public void run(){ //this is the game run loop
System.out.println("this is running");
try{
} catch(Exception e) {} //exception handling
}
public void loadPic(){ //loads the picture from the other project but its the same pic
cat = new ImageIcon("C:\\Users\\Camtronius\\Documents\\NetBeansProjects\\Moving Block Proj\\src\\MovingBlock\\catIcon1.png").getImage(); //gets the image
System.out.println("Image Loaded!");
}
#Override public void paintComponent(Graphics g){
super.paintComponent(g); //paints the component, the picture, on top
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(cat, xCoord, yCoord, null);
g2d.setColor(Color.BLUE);
Ground = new Rectangle(0,450,550,50);
g2d.fillRect(0,450, 550, 50);
for(Rectangle blocknum : blocks){
if (blocks != null) {
g2d.setColor(Color.RED);
g2d.fillRect(xCreate,yCreate,50,50);
System.out.println(blocknum);
}
}
//move();
}
public void move(){
if(yCreate<400){
yCreate+=1;
}else{
}
if(Ground.intersects(blocks[blocknum])){
yCreate=400;
System.out.println("contains!");
}
}
private class Handlerclass implements MouseListener, MouseMotionListener{
public void mouseClicked(MouseEvent event){
}
public void mousePressed(MouseEvent event){
}
public void mouseReleased(MouseEvent event){
if(blocknum<blocks.length){
xCreate=event.getX();
yCreate=event.getY();
blocks[blocknum] = new Rectangle(50,50, xCreate, yCreate);
repaint();
}
blocknum=blocknum+1;
}
public void mouseEntered(MouseEvent event){
}
public void mouseExited(MouseEvent event){
}
public void mouseDragged(MouseEvent event){
}
public void mouseMoved(MouseEvent event){
statusbar.setText(String.format("Coordinates are: %d, %d", event.getX(),event.getY()));
xCoord=event.getX();
yCoord=event.getY();
}
}
}
Painting is a destructive process. That is, when a new paint cycle runs, the previous contents of the Graphics context should be cleared...
So, in you paintComponent method you are only painting the last block...
if(isClicked = true){
blocks[blocknum] = new Rectangle(50,50, xCreate, yCreate);
g2d.setColor(Color.RED);
g2d.fillRect(xCreate,yCreate,50,50);
System.out.println(blocknum);
repaint(); // THIS IS A BAD IDEA
}
DO NOT call any method that might cause repaint to be called. This will put you in a potential cycle of death that will consume your CPU.
Instead, you should loop through the blocks array and paint each one...
for (Rectangle block : blocks) {
if (block != null) {
g2d.setColor(Color.RED);
g2d.fill(block);
}
}
And in you mouseReleased method, you should be adding the new rectangles...
public void mouseReleased(MouseEvent event){
blocknum=blocknum+1;
if (blocknum < blocks.length) {
xCreate=event.getX();
yCreate=event.getY();
blocks[blocknum] = new Rectangle(xCreate, yCreate, 50, 50);
}
}
I'd suggest you take a look at Custom Painting, Painting in AWT and Swing and Concurrency in Swing for more details
Pretty much like the title says - I've got a JPanel, and I'd like to have it at 90% opacity if inactive, and full opacity if moused over.
I've got the separate components working - the mouse over and out is OK and I can change the opacity from overriding the paintComponent method, but I suppose I'm having trouble with the connection between the MouseAdapter and the paintComponent.
It seems there's probably a really easy way to do this - any tips?
(BTW sorry left the code at home so no example for now :( unless it's not quickly solvable then I'll throw some code up tomorrow.)
If you are overriding the paintComponent method, you should be able to add an opacity variable to the JPanel extension. Modify this in the MouseAdapter (using mutators). Then refer to this variable in the overridden paintComponent method to determine how to paint.
If you override the paintComponent method already, I'd suggest you make the MouseAdapter an anonymous inner class of your Panel and let it manipulate a private boolean flag.
public class FadingPanel extends JPanel
{
private boolean active;
public FadingPanel()
{
createMouseAdapter();
}
private void createMouseAdapter()
{
this.addMouseListener(new MouseAdapter()
{
// your mouseadapter code here toggling the active flag
}
}
#Override
public boolean paintComponent(Graphics g)
{
if(active)
{
super.paintComponent(g);
}
else
{
// your semitransparent painting code here
}
}
}
Shoot, I don't have the Haase and Guy book with me, and I don't remember the way they recommend to code for translucent components, but I guess overriding either paint or paintComponent work except that overriding paint will show the effect on child components from the get-go. For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class OpaqueJPanels {
private static void createAndShowUI() {
JPanel mainPanel = new JPanel(new GridLayout(1, 0));
mainPanel.add(new OpaqueJPanel(false, "Override paintComponent"));
mainPanel.add(new OpaqueJPanel(true, "Override paint"));
JFrame frame = new JFrame("Opaque JPanels");
frame.getContentPane().add(mainPanel);
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();
}
});
}
}
class OpaqueJPanel extends JPanel {
private static final int OJP_WIDTH = 250;
private static final int OJP_HEIGHT = OJP_WIDTH;
private static final Composite TRANSLUSCENT_COMPOSITE = AlphaComposite
.getInstance(AlphaComposite.SRC_OVER, 0.4f);
private static final Composite NON_TRANSLUSCENT_COMPOSITE = AlphaComposite
.getInstance(AlphaComposite.SRC_OVER, 1.0f);
private boolean overridePaint;
private boolean transluscent = true;
public OpaqueJPanel(boolean overridePaint, String title) {
add(new JButton("Button"));
setBorder(BorderFactory.createTitledBorder(title));
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
transluscent = false;
getParent().repaint();
}
#Override
public void mouseExited(MouseEvent e) {
if (!OpaqueJPanel.this.contains(e.getPoint())) {
transluscent = true;
getParent().repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(OJP_WIDTH, OJP_HEIGHT);
}
#Override
public void paint(Graphics g) {
if (!overridePaint) {
super.paint(g);
return;
}
Graphics2D g2 = (Graphics2D) g;
Composite composite = transluscent ? TRANSLUSCENT_COMPOSITE
: NON_TRANSLUSCENT_COMPOSITE;
g2.setComposite(composite);
super.paint(g);
}
#Override
protected void paintComponent(Graphics g) {
if (overridePaint) {
super.paintComponent(g);
return;
}
Graphics2D g2 = (Graphics2D) g;
Composite composite = transluscent ? TRANSLUSCENT_COMPOSITE
: NON_TRANSLUSCENT_COMPOSITE;
g2.setComposite(composite);
super.paintComponent(g);
}
}
I also found that it was better if I repainted the JPanel's parent component rather than the JPanel itself.