Pause before painting the panel in Java - java

I am trying to slow down the painting by adding a pause between two consecutive paints. Thread.sleep() apparently doesn't work. Here is the code:
import javax.swing.*;
import java.awt.*;
public class Sa {
int x = 70;
int y = 70;
public static void main(String[] args) {
Sa gui = new Sa();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
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(1500);
} catch(Exception ex) {}
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
Thread.sleep(1500); // will not work!!
g.setColor(Color.green);
g.fillOval(x, y, 80, 40);
}
}
}

Remove Thread.sleep() inside paint() method, not need it, and second, you Thread.sleep() needs to be caught InterruptedException, it may give an error while compiling:
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
//Thread.sleep(1500); // will not work!! (DONT NEED this
g.setColor(Color.green);
g.fillOval(x, y, 80, 40);
Have you looked at Swing Timer ?

Related

JFrame graphics ignores the first few renders

Here is a minimal code to see the bug:
import javax.swing.*;
import java.awt.*;
public class Main1 extends JFrame {
static Main1 main;
public Main1() {
super("app");
}
public static void main(String[] args) {
main = new Main1();
main.setBounds(300, 300, 800, 500);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
Graphics g = main.getGraphics();
for(int i = 0; i < 100; i++){
g.setColor(new Color(255, 0, 0));
g.fillRect(0, 0, 800, 500);
}
}
}
If i use 100 in the "for" cycle, the frame appears not to be colored, but 200 loops is enough to color it.
I want to make an application where frames change rarely, but this feature ruins the quality of code because I have to make a number of dummy frames.
public static void main(String[] args) {
main = new Main1();
main.setBounds(300, 300, 800, 500);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
Graphics g = main.getGraphics();
for(int i = 0; i < 100; i++){
g.setColor(new Color(255, 0, 0));
g.fillRect(0, 0, 800, 500);
}
}
This is not how you do Swing graphics. Getting a Graphics object by calling .getGraphics() on a component gives you a short-lived unstable and sometimes null object. For instance, it takes some time for the created JFrame to render, and if you call getGraphics() and try to use it prior to rendering, the object may be null, and certainly won't wokr.
Instead paint within a JPanel's paintComponent method using the Graphics object given by the JVM as per the tutorials:
public class MainPanel extends JPanel {
public MainPanel {
setPreferredSize(new Dimension(800, 500)));
setBackground(new Color(255, 0, 0)); // if you just want to set background
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use g here do do your drawing
}
}
and then use it like so:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
Tutorial: Lesson: Performing Custom Painting
And yes, if you want to drive a simple animation, use a Swing Timer to help drive it like so:
public class MainPanel extends JPanel {
private int x = 0;
private int y = 0;
public MainPanel {
setPreferredSize(new Dimension(800, 500)));
setBackground(new Color(255, 0, 0)); // if you just want to set background
// timer code:
int timerDelay = 15;
new Timer(timerDelay, ()-> {
x += 4;
y += 4;
repaint();
}).start();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use g here do do your drawing
g.setColor(Color.BLUE);
g.drawRect(x, y, 20, 20);
}
}

ActionListener works but painting doesn't

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Game extends JComponent implements ActionListener {
Timer t = new Timer(5, this);
int wx;
int rx = 10;
int rx2 = 10;
int carx = 10;
int velX = 2;
public static void main(String[] args) {
JFrame window = new JFrame("Frogger");
window.add(new Game());
window.pack();
window.setSize(800, 600);
window.setLocationRelativeTo(null);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setVisible(true);
}
public void actionPerformed(ActionEvent e){
carx+=velX;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
repaint();
g.setColor(new Color(173, 216, 230));
g.fillRect(0, 0, 800, 600); //background
g.setColor(Color.lightGray);
g.fillRect(0, 525, 800, 75); //start
g.fillRect(0, 0, 800, 30); //end
g.setColor(Color.black);
g.fillRect(0, 275, 800, 250); //street
g.setColor(Color.white);
for (int n = 0; n < 16; n++) {
g.fillRect(rx, 450, 20, 10);
rx += 50;
}
for (int n = 0; n < 16; n++) {
g.fillRect(rx2, 375, 20, 10);
rx2 += 50;
}
g.fillRect(carx, 477, 60, 30);
t.start();
}
}
I am trying to make a Frogger game and am having trouble creating the traffic. I am able to make a car move across the street but the lines separating the lanes are shown for a millisecond and then disappear after I run the program. The street, river, start, and end all show up as I want them to. How do I make the lane lines not disappear?
There are a couple of problems with what you are doing.
Firstly, you are calling t.start() every time the component is drawn. This is unnecessary. Instead of doing this, create a boolean value determining whether it is the first frame and start it then. Here is how you can do this:
boolean firstFrame = true;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(firstFrame){
t.start();
firstFrame = false;
}
//rest of render code...
}
Now for your question of how to stop the lines disappearing. You seem to store the integers rx and rx2 as members of the Game class. This means when you add to them, they stay added until reset. Therefore, every frame, you must reset rx and rx2 to 10.
At the end of paintComponent, add this.
rx = rx2 = 10;
This will set both rx and rx2 back to their starting value of 10.

Drawing a Triangle Component using pen operation

How to do it? I mean, I can do it for Ellipse, but not sure about triangle.
You can use a Polygon.
int[] xPoints = {0, 0, 30};
int[] yPoints = {0, 30, 30};
Shape s = new Polygon(xPoints, yPoints, 3);
g2d.fill(s);
This doesn't answer your current question.
It demonstrates why you should NOT use panel.getGraphics() to do your painting. Painting done with the getGraphics() method is not permanent.
Try minimizing or maximizing the frame and see what happens to the painting:
import java.awt.*;
import javax.swing.*;
public class SSCCE2
{
private static void createAndShowGUI()
{
final JPanel panel = new JPanel()
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(0, 0, 50, 50);
}
};
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setLocationByPlatform( true );
frame.setSize(300, 300);
frame.setVisible( true );
Graphics g = panel.getGraphics();
g.setColor(Color.RED);
g.fillOval(100, 100, 50, 50);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Graphics g = panel.getGraphics();
g.setColor(Color.RED);
g.fillOval(100, 100, 50, 50);
}
});
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}

How to decrease a height of a rectangle? (Java, AWT)

I'm beginner in Java. So, please help me with my problem.
I can do animation when a rectangle's height increases. But I have problem with decreasing rectangle's height. Please look at this code:
public class Animation extends JPanel implements ActionListener {
Timer timer;
int i = 100;
public Animation() {
timer = new Timer(10, this);
timer.start();
}
public void paint(Graphics g) {
Graphics2D g2d1 = (Graphics2D) g;
g2d1.fillRect(0, 100, 30, i);
}
public static void main(String[] args) {
JFrame frame = new JFrame("animation");
frame.add(new Animation());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 800);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
--i;
repaint();
}
}
Please help me.
Best regards
Pawel
It isn't clearing the screen between draws, so it draws over the old larger rectangle.
Try this:
public void paint(Graphics g) {
Graphics2D g2d1 = (Graphics2D) g;
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight()); // draw a rectangle over the display area in the bg color
g.setColor(Color.BLACK);
g2d1.fillRect(0, 100, 30, i);
}
Or:
public void paint(Graphics g) {
super.paint(g); // call superclass method, which does clear the screen
Graphics2D g2d1 = (Graphics2D) g;
g2d1.fillRect(0, 100, 30, i);
}
And as camickr pointed out below, custom painting should be done in paintComponent not paint, so you should change the name of the method to paintComponent.

Getting Unexpected output with the swing code

I'm trying to built a simple app which has a translucent frame and it draws lines where the user wants.I have also added listeners to catch the mouse events and these are displayed accordingly .Everything is working fine but the problems are:
1)the window is not transparent
2)it is completely black and the lines are appearing white.
Can anyone
Here is the code:
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseListen2 extends JFrame implements MouseListener {
String str = "Nothing";
int x[][] = new int[100][2];
int count = 0;
int flag = 1;
boolean draw = false;
MouseListen2() {
super("Line Draw App");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
this.addMouseListener(this);
setBackground(new Color(0, 0, 0, 0));
JPanel jp = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Paint gp = new GradientPaint(300, 700, new Color(20, 20, 210, 0), 100, 00, new Color(10, 20, 40, 255));
g2.setPaint(gp);
g2.fillRect(0, 0, getWidth(), getHeight());
}
};
setContentPane(jp);
setVisible(true);
//c.setOpaque(true);
}
public void paint(Graphics g) {
//Graphics g=this.getGraphics();
//super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.clearRect(0, 0, getWidth(), getHeight());
g2.drawString(str, 50, 50);
//initially count=0 hence i<-1 so loop will not automatically run in the beginning
for (int i = 0; i < count - 1; i = i + 2) {
g2.drawLine(x[i][0], x[i][1], x[i + 1][0], x[i + 1][1]);
}
//repaint(); using this here creates an infinite loop as after mouse event paint is called and at the end
//this method is again called using the repaint() and so on the loop continues.
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MouseListen2();
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
str = "clicked";
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
str = "pressed";
repaint();
x[count][0] = e.getX();
x[count][1] = e.getY();
count++;
}
#Override
public void mouseReleased(MouseEvent e) {
str = "released";
draw = true;
x[count][0] = e.getX();
x[count][1] = e.getY();
count++;
//draw();
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
str = "entered";
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
str = "exited";
repaint();
}
}
have to add MouseListener to the JPanel, because you added MouseListener to the JFrame (this.addMouseListener(this);)
this code line setContentPane(jp); put JPanel to the BorderLayout.CENTER possition to the JFrame, in this case (isn't there any another JComponent added to the JFrame) fills whole / all available space into JFrame
then for mouse event is accesible only JPanel, mouse can't access to the JFrame's RootPane or ContentPane
remove / comment public void paint(Graphics g) and rellated code block move to the paintComponent for the JPanel
See How to Create Translucent and Shaped Windows.

Categories

Resources