Java JFrame render lagging - java

I'm trying to make a simple game in java using the swing engine. However currently I am having issues with lag. This simple code draws a circle and moves it from the top left corner of the frame to the bottom right corner, but it lags a lot. While my pc is somewhat old, i3 4gb ram, I think it should manage to perform this without lag?
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.Timer;
public class Game extends JPanel implements ActionListener {
public Timer timer;
int x = 0;
int y = 0;
public Game() {
timer = new Timer(20, this);
timer.start();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.fillOval(x, y, 15, 15);
}
public void actionPerformed(ActionEvent e) {
x++;
y++;
repaint();
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("test");
Game game = new Game();
frame.add(game);
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

Related

Simple Java Swing Animation Lag

I am a java beginner and I'm having trouble with a simple swing animation I created. The animation lags when running unless something else is happening like mouse movement or a key being pressed down. I have searched for answers but none of them solve this problem.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Animation extends JPanel implements ActionListener {
Timer timer = new Timer(5, this);
int y = 0, velY = 2;
public void actionPerformed(ActionEvent e) {
y += velY;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRect(50, y, 50, 50);
timer.start();
}
public static void main(String[] args) {
Animation drawPanel = new Animation();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
frame.add(drawPanel);
}
}
First and foremost, get that timer.start() out of your paintComponent method since it does not belong there, and serves no purpose other than to slow the rendering down. Instead you should call that method once, and once only.
Next, 5 mSecs may be an unrealistic timer delay. Experiment with this number, but expect to get a decent functioning somewhere near 10 to 15 mSecs.
Next, base your position change on actual time slice differences that have been measured, not on what you're hoping the timer is doing.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Animation extends JPanel {
private static final int TIMER_DELAY = 16;
private static final double Y_VELOCITY = 0.05;
private double dY = 0.0;
private Timer timer = new Timer(TIMER_DELAY, new TimerListener());
public Animation() {
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRect(50, (int) dY, 50, 50);
// timer.start();
}
private class TimerListener implements ActionListener {
private long prevTime;
#Override
public void actionPerformed(ActionEvent e) {
if (prevTime == 0L) {
repaint();
prevTime = System.currentTimeMillis();
} else {
long currentTime = System.currentTimeMillis();
long deltaTime = currentTime - prevTime;
double deltaY = Y_VELOCITY * deltaTime;
dY += deltaY;
prevTime = currentTime;
repaint();
}
}
}
public static void main(String[] args) {
Animation drawPanel = new Animation();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
frame.add(drawPanel);
}
}

Draw Rectangular2D using Swing on JPanel, and display the shape resizing

I have started reading Performing custom paint with swing. I wanted to extend what I read on the tutorial and draw rectangle "live". Not just the rectangle to pop up and show on the panel, but I wanted visually see the Rectangle shape resize as I drag the mouse, and finally when I release the mouse I wanted it to appear on the JPanel. I have included below what I did so far with a research and reading. The problem is since I am trying to catch each Rectangualr2D(this is the class I want to use) shape with mouse drag it end up looking like having a black background shape. How can I accomplish my target? Thanks for suggestions as always.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
class RectTool {
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.add(new DPanel());
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class DPanel extends JPanel {
ArrayList<Rectangle2D.Double> linesBasket = new ArrayList<Rectangle2D.Double>();
Rectangle2D.Double rect;
final static BasicStroke stroke = new BasicStroke(5.0f);
double p1d ;
double p2d;
public DPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
setBackground(Color.white);
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
final double startPointX = e.getX(); ;
final double startPointY = e.getY();
//current
rect.setRect(startPointX,startPointY,p1d,p2d);
}
public void mouseReleased(MouseEvent e){
linesBasket.add(rect);
}
});
addMouseMotionListener(new MouseAdapter(){
public void mouseDragged(MouseEvent e){
p1d = e.getX();
p2d = e.getY();
rect.setRect(10,10,p1d,p2d);
rect.setRect(rect);
repaint();
}
});
}
public void repaintShapeBasket(Graphics g){
rect = new Rectangle2D.Double();
rect.setRect(rect);
Graphics2D g2 = (Graphics2D) g;
linesBasket.add(rect);
for (Rectangle2D.Double rect : linesBasket) {
g2.draw(rect);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
repaintShapeBasket(g);
}
}

How to move JFrame shape

I'm trying to develop a simple game. The games is about the shapes. Shapes will move and we'll catch by mouse. I have already created a oval and given size of oval graphic. But I cannot move this shape repeatedly. I think I need to use timer class. I have been trying 2 hours myself but I didnt do yet.
The code;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class myshapestry extends JFrame implements ActionListener {
JFrame frame=new JFrame("Deneme");
Container l ;
private static int ballX=150;
private static int ballY=150;
myshapestry() {
l=this.getContentPane();
l.setLayout(null);
MyPanel panel=new MyPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.add(panel);
frame.setVisible(true);
frame.setSize(getPreferredSize());``
}
public Dimension getPreferredSize() {
return new Dimension(500,600);
}
public static void main (String args[]){
myshapestry tr=new myshapestry();
tr.setTitle("Game of Shapes");
}
private static class MyPanel extends JPanel {
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.fillOval(ballX, ballY,50 , 70);
}
public void actionPerformed(ActionEvent e){
ballX = ballX + 5;
ballY = ballY + 10;
repaint();
}
}
}
I was trying these code in the myshapestry code block;
Timer timer=new Timer(100,myshapestry);
t.start();
Add something like this
javax.swing.Timer timer=new javax.swing.Timer(100, panel) ;
timer.start();
Each 100msec the timer invokes actionPerformed() method of your MyPanel class

Java is drawing 2 boxes

So I am making a little game to learn some graphical java and I am having trouble with a button. It is drawing 2, one is the correct size and in the correct location and then there is a very small button centered at the top of the application. THere should only be the one button at (0,0,200,50). I do not know what is wrong but here is the code for the button, if you need something more then this let me know!
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
EDIT1: the 2 classes where error will be: board.java:
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Board extends JPanel {
public Board() {
}
#Override
public void paintComponent(Graphics g) {
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
}
private void drawRectangle(Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawRect(x, y, width, height);
}
}
and the main:
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class main extends JFrame {
public main() {
initUI();
}
private void initUI() {
add(new Board());
setSize(800, 600);
setTitle("Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
main ex = new main();
ex.setVisible(true);
}
});
}
}
If you try to resize window, you will see that buttons are spawning.
This happens because of your paintComponent method, which is called every painting iteration.
You should move button addition, for example, to constructor which is called once:
public Board() {
ImageIcon test = new ImageIcon("nhButton.png");
JButton jb = new JButton(test);
jb.setBounds(0, 0, 200, 50);
jb.setVisible(true);
add(jb);
}

paintComponent draws other components on top of my drawing

I'm trying to build a simple paint tool. The mouseDrag events creates a new ellipse and causes my JPanel to repaint().
This works fine so far.
However, if I press any button (or any other UI component) before firing the mouseDrag event for the first time, the button is painted in the upper left corner of my panel.
I have isolated the code into this test application:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame
{
public Test()
{
final JPanel paintPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setPaintMode();
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(100, 100, 10, 10);
}
};
paintPanel.setPreferredSize(new Dimension(300,300));
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e)
{
paintPanel.repaint();
}
});
this.setLayout(new FlowLayout());
this.add(paintPanel);
this.add(new JButton("Dummy"));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String... args)
{
new Test();
}
}
A Screenshot for "seeing" the problem in my Main application
+1 to #MadProgrammer's answers.
You should have super.paintComponent(..) as the first call in your overriden paintComponent()
Do not extend JFrame unnecessarily
Create and minipulate Swing components via EDT
Dont call setPrefferedSize() rather override getPrefferedSize()
Here is an example which incorporates my advice's and #MadProgrammer's:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
JFrame frame;
public Test() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final PaintPanel paintPanel = new PaintPanel();
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
paintPanel.addRect(e.getX(), e.getY());
}
});
frame.setLayout(new FlowLayout());
frame.add(paintPanel);
frame.add(new JButton("Dummy"));
frame.pack();
frame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class PaintPanel extends JPanel {
public PaintPanel() {
addRect(100, 100);
}
ArrayList<Rectangle> rects = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaintMode();
for (Rectangle r : rects) {
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(r.x, r.y, r.width, r.height);
}
}
public void addRect(int x, int y) {
rects.add(new Rectangle(x, y, 10, 10));
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
You're not calling super.paintComponent.
The graphics context used for a paint cycle is shared between all the components begin painted, this means if you don't take care to clear it before painting onto, you will end up with what ever was painted before you.
One of the jobs of paintComponent is to prepare the graphics for painting

Categories