I wrote this program which animates a red rectangle, using JCreator, I am finding difficulty in running the annimation, does anybody have any suggestions?
This is the program which animates the rectangle:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Tutorial extends JPanel implements ActionListener
{
Timer tm = new Timer(5, this);
int x = 0 , velX = 2;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x, 30, 50, 30);
tm.start();
}
public void actionPerformed(ActionEvent e){
x = x + velX;
repaint();
}
}
Related
I need to write a generic method that draw a centered String. In order to do that I need to know the width of the String and in order to calculate that I have different alternatives:
Rectangle2D rect=Toolkit.getDefaultToolkit().getFontMetrics(gc.getFont()).getStringBounds(text, gc);
or
AffineTransform affinetransform = new AffineTransform();
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);
Rectangle2D rect=gc.getFont().getStringBounds(text, frc);
or
FontMetrics metrics = g.getFontMetrics(font);
metrics.stringWidth(text)
But does't matter which approach I use it takes around 1 second to calculate that, that's crazy I'm using Eclipse with Java 1.8.0_121 on a on Macbook 3,1 GHz Intel Core i7, that's crazy!
What is wrong with it?
First Example:
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("Demo");
Container cp = jf.getContentPane();
MyCanvas1 tl = new MyCanvas1();
cp.add(tl);
jf.setSize(300, 200);
jf.setVisible(true);
}
}
class MyCanvas1 extends JComponent {
public void paint(Graphics g) {
long start=System.currentTimeMillis();
Graphics2D g2 = (Graphics2D) g;
drawCenteredString(g2, "Example", getBounds(), g.getFont());
System.out.println("executed in:"+(System.currentTimeMillis()-start));
}
public void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
FontMetrics metrics = g.getFontMetrics(font);
int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
// Determine the Y coordinate for the text (note we add the ascent, as in java 2d 0 is top of the screen)
int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent();
// Set the font
g.setFont(font);
// Draw the String
g.drawString(text, x, y);
}
}
executed in:922
Example 2:
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("Demo");
Container cp = jf.getContentPane();
MyCanvas1 tl = new MyCanvas1();
cp.add(tl);
jf.setSize(300, 200);
jf.setVisible(true);
}
}
class MyCanvas1 extends JComponent {
public void paint(Graphics g) {
long start=System.currentTimeMillis();
Graphics2D g2 = (Graphics2D) g;
drawCenteredString(g2, "Example", getBounds(), g.getFont());
System.out.println("executed in:"+(System.currentTimeMillis()-start));
}
public void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
AffineTransform affinetransform = new AffineTransform();
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);
Rectangle2D rect2=font.getStringBounds(text, frc);
// Draw the String
g.drawString(text, (int) (rect.width/2-rect2.getWidth()/2),(int) (rect.height/2-rect2.getHeight()/2));
}
}
executed in:916
Example 3:
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("Demo");
Container cp = jf.getContentPane();
MyCanvas1 tl = new MyCanvas1();
cp.add(tl);
jf.setSize(300, 200);
jf.setVisible(true);
}
}
class MyCanvas1 extends JComponent {
public void paint(Graphics g) {
long start=System.currentTimeMillis();
Graphics2D g2 = (Graphics2D) g;
drawCenteredString(g2, "Example", getBounds(), g.getFont());
System.out.println("executed in:"+(System.currentTimeMillis()-start));
}
public void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
AffineTransform affinetransform = new AffineTransform();
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);
Rectangle2D rect2=Toolkit.getDefaultToolkit().getFontMetrics(font).getStringBounds(text, g);
// Draw the String
g.drawString(text, (int) (rect.width/2-rect2.getWidth()/2),(int) (rect.height/2-rect2.getHeight()/2));
}
}
executed in:908
It seems somebody else had a similar problem but without any solution:
Java: Fastest way to draw text?
Does somebody see where the problem could be?
EDIT:
Just an update using Java 8u221 same results, using the latest Java 13 I got a little improvement instead of 900 they are executed in around 700 milliseconds... I cannot believe that... It seems this operations are very slow on Mac... doesn't matter the Java version I use...
EDIT2:
Even executing this code:
public class Main {
public static void main(String[] args) {
long start=System.currentTimeMillis();
BufferedImage image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
drawCenteredString(g2, "Example", new Rectangle (0,0,300,300), g2.getFont());
System.out.println("executed in:"+(System.currentTimeMillis()-start));
}
public static void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
Rectangle2D rect2=Toolkit.getDefaultToolkit().getFontMetrics(font).getStringBounds(text, g);
// Draw the String
g.drawString(text, (int) (rect.width/2-rect2.getWidth()/2),(int) (rect.height/2-rect2.getHeight()/2));
}
}
I get: executed in:1342
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);
}
}
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);
}
}
I have quite a similar problem to answered before in keyword in title, but I have the situation not satisfied me. In this part of code I wont to show current position of "craft". I can see it in console (function craft.Print()), but also want to have it in label. The label exist, but or is not "live" or in every loop is copied and fills the screen. I commented the way to make it visible only one time, but it is not pretty way to do it I think.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.border.Border;
public class Board extends JPanel implements ActionListener {
int i=0;
Craft craft = new Craft();//this is object to be moved
private static final long serialVersionUID = 1L;
private Timer timer;
private final int DELAY = 100;
public Board() {
initBoard();
}
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
timer = new Timer(DELAY, this);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
// if(craft.getX()==30&&craft.getY()==30&&i==0){
JLabel label = new JLabel("It is, but I wont this to be live:"+craft.getX());//craft.getX() current position of the craft
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setVerticalAlignment(SwingConstants.TOP);
label.setBackground(Color.GRAY);
label.setForeground(Color.WHITE);
Border border = BorderFactory.createLineBorder(Color.blue);
label.setBorder(border);
revalidate();
add(label);
repaint();
i=1;
// }
craft.Print();//to watch position in console
super.paintComponent(g);
doDrawing(g);
Toolkit.getDefaultToolkit().sync();
}
private void doDrawing(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);
g2d.setColor(Color.RED);
g2d.drawRect(craft.HallEntry[0],craft.HallEntry[1],
craft.PPDX,craft.PPDY);
g2d.setColor(Color.GREEN);
g2d.drawRect(craft.BathroomEntry[0], craft.BathroomEntry[1],
craft.DLX,craft.DLY);
g2d.setColor(Color.BLUE);
g2d.drawRect(craft.LivingRoomEntry[0],craft.LivingRoomEntry[1],
craft.DSX,craft.DSY);
g2d.setColor(Color.PINK);
g2d.drawRect(craft.KitchenEntry[0],craft.KitchenEntry[1],
craft.DKX,craft.DKY);
}
#Override
public void actionPerformed(ActionEvent e) {
craft.move();
repaint();
}
public class TAdapter extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
craft.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
craft.keyPressed(e);
}
}
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);
}