package games;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class viza extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
int x=0, y=200;
Timer tm =new Timer(5,this);
public viza(){
tm.start();
}
public void paintComponent(Graphics g){
g.setColor(Color.red);
g.fillRect(x, y, 20, 20);
}
public void actionPerformed(ActionEvent e){
x=x+1;
y=y+1;
if(x>300)
x=0;
if(x<0)
x=0;
repaint(); //after x and y are changet then I use repaint();
} // the frame is created and the new object is added into the frame.
public static void main(String[] args){
viza a=new viza();
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.add(a);
frame.setVisible(true);
}
}[1]
The code is used to draw a filled rectangle on the panel. However when I start the program the object moves but the panel is not repainted. If I try and resize the window while the program is runing it does load properly. As soon as i stop doing that the panel or frame (Not sure) is not repainted anymore. So i end up whith a line.
You should clear the underlying pane before you re-draw the rectangle in its new position.
To do that, let the super.paintComponent() do that for you, since that would be the correct approach to custom painting in any JComponent:
public void paintComponent(Graphics g){
super.paintComponent(g); // let it do the default paint
g.setColor(Color.red);
g.fillRect(x, y, 20, 20);
}
Also you may want to add a default close operation to your frame (in main method) to exit the program after closing the frame:
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Another tip is to set a bigger timeout for your Timer, because 5 milliseconds is occurring very fast and your user may not see the movement. Try something bigger than 50 or 100.
Good Luck.
Related
On Head First Java book we're seeing some little animation and I'm trying to draw an animation that traces out a diagonal line. I'm doing so by using the paintComponent() method and drawing an oval at x,y (values which are updated each time through the loop). Why do I lose the previously drawn ovals? According to the book I should be getting a smear on the screen where the previously drawn ovals are not lost. This should need fixing by adding to the paintComponent() method a white background every time repaint() is called but instead i'm not getting the 'mistake'. Why is this and how do I get to KEEP the previously drawn ovals on the panel? Using JDK 13.0.2 and Mac OSX Catalina
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation {
int x = 70;
int y = 70;
public static void main(String[] args) {
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
MyDrawPanel drawPanel = new MyDrawPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel);
frame.setSize(300,300);
frame.setVisible(true);
for (int i = 0; i < 130; i++) {
x++;
y++;
drawPanel.repaint();
try {
Thread.sleep(25);
} catch (Exception ex){};
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.orange);
g.fillOval(x,y,50,50);
}
} // close inner class
} // close outer class
Is that what prevents the smear of ovals?
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.orange);
g.fillOval(x,y,50,50);
}
The code should be:
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g); // added
g.setColor(Color.orange);
g.fillOval(x,y,50,50);
}
You need the super.paintComponent(g) to clear the background of the panel before doing the custom painting.
Yeah, great book. The output i'm getting with the code as is, is the "corrected version"
Edit:
The book is correct. You need to understand how the EDT works. When you start an application the code invoked in the main() method executes on a separate Thread. Swing events and painting is done on the Event Dispatch Thread (EDT). So invoking sleep() in the go() method should NOT affect the painting of the circle and you should see the smear. If you only see a single oval painted after the loop is finished, then this imples your IDE or platform starts the code in the main() method on the EDT, which is not normal.
You can verify my above statement by adding:
System.out.println( SwingUtilities.isEventDispatchThread() );
to your loop to see if it is executing on the EDT or not.
This question already has answers here:
Why does the first panel added to a frame disappear?
(2 answers)
Closed 5 years ago.
I've been trying all day long to make this happen with no success. What can be going wrong?
I want 2 threads printing simultaneously in my JFrame:
Thread-1: Prints Squares
Thread-2: Prints Circles
I'am ending up with only one thread printing on the JFrame. The other get executed but don't print in the JFrame.
Look, only squares are getting printed:
This is my main class:
public class Main {
public static void main(String[] args) {
FigurePlacer circle = new FigurePlacer("circle");
FigurePlacer square = new FigurePlacer("square");
JFrame window = new JFrame();
window.add(circle);
window.add(square);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("Task");
window.setSize(700, 700);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
This is the Threading Class:
import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import java.util.Random;
public class FigurePlacer extends JPanel implements Runnable{
String figure;
final int width = 700;
final int height = 700;
int x_pos = 0;
int y_pos = 0;
int x_width = 50;
int y_height = 50;
public FigurePlacer(String str){
figure = str;
randomCoord();
Thread th = new Thread (this);
th.start();
}
private void randomCoord(){ //this ramdomize x,y coord to place a new object
Random random = new Random();
x_pos = random.nextInt(width);
y_pos = random.nextInt(height);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK); //sets the black color in background
g.fillRect(0, 0, 700, 700);
System.out.println(figure);
switch (figure){
case "square":
g.setColor(Color.GREEN);
g.fillRect(x_pos, y_pos, x_width, y_height);
break;
case "circle":
g.setColor(Color.BLUE);
g.fillOval(x_pos, y_pos, x_width, y_height);
break;
}
}
#Override
public void run(){ //paints the objects
while (true){
randomCoord();
paintImmediately(x_pos, y_pos, x_width, y_height);
try{
Thread.sleep (50);
}
catch (InterruptedException ex){}
}
}
}
JFrame window = new JFrame();
window.add(circle);
window.add(square);
The default layout manager for a JFrame is the BorderLayout. When you add a component to a panel using the BorderLayout and don't specify a constraint then the component goes to the CENTER. However only one component can ever be displayed in the CENTER, so only the last component added is painted.
You could use the OverlayLayout, which allows you to stack two panels on top of one another. Of course you will need to make the top panel non-opaque.
The easier solution is to not attempt to use two panels, just create on panel that can display circles or squares.
Also, your painting code is wrong. You should not be using paintImmediately(...) to do painting. The paintComponent() method should paint every object every time the method is invoked. Try resizing your frame and you will see that all your object disappear since the paintComponent() method will clear all the old paintings.
See Custom Painting Approaches for the two common approaches for this kind of painting.
I am working on a simple object drawing program using Swing in Java.
My program simply should draw shapes according to buttons when clicked, and move any shapes with the mouse. I have four buttons which draw rectangle, circle and square on screen. So far I did managed to draw to shapes when you click on buttons. but i want to move the shapes on screen which it did not work out.
The problem is this: When I click on circle shape to drag it around with mouse, it clears all the screen and noting is on the screen.
And, is there a way to clean all the screen when I click on clear button?
Thank you?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintProject extends JComponent implements ActionListener,
MouseMotionListener {
private int CircleX=0;
private int CircleY=0;
private int RectX=100;
private int RectY=100;
private int SquareX=300;
private int SquareY=200;
public static void main(String[] args) {
JFrame frame = new JFrame("NEW PAINT PROGRAME!");
JButton CircleButton = new JButton("Circle");
CircleButton.setActionCommand("Circle");
JButton RectangleButton = new JButton("Rectangle");
RectangleButton.setActionCommand("Rectangle");
JButton SquareButton = new JButton("Square");
SquareButton.setActionCommand("Square");
PaintProject paint = new PaintProject();
CircleButton.addActionListener(paint);
RectangleButton.addActionListener(paint);
SquareButton.addActionListener(paint);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(paint);
frame.add(CircleButton);
frame.add(RectangleButton);
frame.add(SquareButton);
frame.addMouseMotionListener(paint);
frame.pack();
frame.setVisible(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
private void drawCircle() {
Graphics g = this.getGraphics();
g.setColor(Color.red);
g.fillOval(CircleX, CircleY, 100, 100);
}
private void drawRectangle() {
Graphics g = this.getGraphics();
g.setColor(Color.green);
g.fillRect(RectX, RectY, 100, 300);
}
private void drawSquare() {
Graphics g = this.getGraphics();
g.setColor(Color.blue);
g.fillRect(SquareX, SquareY, 100, 100);
}
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Circle")) {
drawCircle();
}
else if (command.equals("Rectangle")) {
drawRectangle();
}
else if (command.equals("Square")) {
drawSquare();
}
}
#Override
public void mouseDragged(MouseEvent e) {
CircleX=e.getX();
CircleY=e.getY();
repaint();
}
}
As noted here and here, getGraphics() is not how to perform custom painting in Swing. Instead, override paintComponent() to render the desired content. It looks like you want to drag shapes using the mouse. A basic approach to moving a selected object is shown here; substitute your fillXxx() invocation for the drawString() shown there. For multiple shapes, use a List<Shape>; the clear command then becomes simply List::clear. A complete example is cited here; it features moveable, selectable, resizable, colored nodes connected by edges.
I am able to draw a horizontal line but unable to draw a vertical line. Please help me.
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
class Success extends JFrame{
public Success(){
JPanel panel=new JPanel();
getContentPane().add(panel);
setSize(450,450);
JButton button =new JButton("press");
panel.add(button);
}
public void paint(Graphics g) {
super.paint(g); // fixes the immediate problem.
Graphics2D g2 = (Graphics2D) g;
Line2D lin = new Line2D.Float(20, 40, 850, 40);
g2.draw(lin);
}
public static void main(String []args){
Success s=new Success();
s.setVisible(true);
}
}
Thanks in advance.
Keep the x co-ordinates the same and change value of y co-ordinates as shown below
Line2D lin = new Line2D.Float(20, 40, 20, 150);
First two values are the (x1,y1) value of the starting point of the line and last two values (x2,y2) end point of the line. Now I hope you understand why your code produced a horizontal line and what needs to be done to draw vertical line.
I noticed a couple things, some of them were already pointed out:
To answer your question directly, this is what the (x, y) coordinates look like for Swing components
keep x coordinates the same for a vertical line. If you don't know where the x coordinates are in your line constructor when you create it, look at the documentation for the constructor. If you're using Eclipse, this means you should just hover your mouse over the code that contains the constructor.
Your line goes outside the range of your JFrame; instead, if you want it to go from end to end, use the getWidth() and getHeight() methods.
You shouldn't be creating a new line every time you repaint your components. Instead, you should create the line somewhere in you Success class, implement ActionListener so you can update your code every frame, and in that update, resize your line, then leave just the repainting to paintComponent.
You shouldn't override JFrame in this case, and you usually shouldn't have to.
You should override the paintComponent method, not the paint method.
I don't think you're double-buffering correctly, but I can't help you there.
Overriding the getPreferredSize method of JPanel is handy if you want to control its size, but it's not even necessary in this case, because adding it to the JFrame will automatically size it for you.
There's a lot of stuff that goes on in Swing behind the scenes, and it can get confusing because normally you have to say stuff explicitly, but keep playing with this example, and you should be safe for a while.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.*;
class Success extends JPanel implements ActionListener{
private final Timer timer = new Timer(20, this); // Create a timer that will go off every 20 ms
Line2D horizontalLine; // Declare your variables here, but don't initialize them
Line2D verticalLine; // That way, they can be accessed later in actionPerformed and repaint
// You might want to try frame.setResizable(false) if you want your frame
// and your panel to stay the same size.
private final Dimension prefPanelSize = new Dimension(450, 450);
public Success(){
super(); // Call the constructor of JPanel, the class this subclasses.
JButton button =new JButton("press");
this.add(button);
this.setSize(prefPanelSize);
horizontalLine = new Line2D.Float(0, 40, prefPanelSize.width, 40);
verticalLine = new Line2D.Float(prefPanelSize.width / 2, 0,
prefPanelSize.width / 2, prefPanelSize.height);
timer.start(); // Start the timer
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // fixes the immediate problem.
Graphics2D g2 = (Graphics2D) g;
g2.draw(horizontalLine);
g2.draw(verticalLine);
}
#Override
public Dimension getPreferredSize()
{
return prefPanelSize;
}
public static void main(String []args){
Success s = new Success();
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(new Dimension(450, 450));
frame.add(s);
}
// This method is called ever 20 ms because of the timer.
#Override
public void actionPerformed(ActionEvent e) {
int currWidth = getWidth();
int currHeight = getHeight();
horizontalLine.setLine(0, 40, currWidth, 40);
verticalLine.setLine(currWidth / 2, 0, currWidth / 2, currHeight);
}
}
I have been playing around with Java's 2d painting tools and have hit a snag. I am attempting to move the objects. Here is the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test extends JPanel{
private int[] location = new int[2];
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillArc(location[0], location[1], 100, 100, 45, 90);
g.setColor(Color.black);
g.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);
new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setLocation((location[0]+50),50);
repaint();
System.out.println("repainting");
}
}).start();
}
public void setLocation(int x, int y){
this.location[0] = x;
this.location[1] = y;
}
public static void main(String[] args){
JFrame jf=new JFrame();
jf.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(new Dimension(300,500));
jf.setLocation(100,100);
jf.add(new Test());
jf.pack();
jf.setVisible(true);
}
}
This only paints one of the two objects to the screen... it seems to be the second one as when I change the parameters of setLocation on [1] the one object it does paint moves. Any thoughts? Thanks
Edit: Edited above code to reflect what was said below.
You are adding two components to the JFrame in a default way. This will add the components BorderLayout.CENTER and so the second component will cover and obscure the first. You will want to read up on layout managers to fix this. Also read up on Swing Timers for simple animations, since your code, even if written correctly would do no animation.
If you want to move the drawing, then
Use only one Test JPanel
Override JPanel's paintComponent(...) method, not paint(...) method.
call the super.paintComponent(g) method first thing in your paintComponent method override.
Give the Test JPanel public methods to allow outside classes to change the location without having them directly futz with the field. Make the location field (name should begin with a lower-case letter) private just to be safe.
Use a Swing Timer to periodically call this method and change location, then call repaint() on the JPanel.