I am trying to create a game where I have a background image and text on top of that in the form of JLabels. How would I go about doing that?
The main reason I'm doing this is so that I can have 2 different text areas with different font sizes. Using g.drawString() will only let you use 1 text size for the whole thing.
Here is my code so far:
package com.cgp.buildtown;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class Intro extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
private Thread thread;
private BufferedImage bg;
private Font font;
public Intro() {
super();
loadImages();
setFont(loadFont(50f));
}
private Font loadFont(Float f) {
try {
font = Font.createFont(Font.TRUETYPE_FONT, new File("res/komikatext.ttf"));
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(font);
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
return font.deriveFont(f);
}
private void loadImages() {
try {
bg = ImageIO.read(new File("res/introbg.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void addNotify() {
super.addNotify();
thread = new Thread(this);
thread.start();
}
public void run() {
while(true) {
repaint();
}
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(bg, 0, 0, null);
}
}
Here is one way.
But of course that is merely a version hacked out of your own code/ specs. For a much better implementation of the same idea, see this Background Panel.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;
import javax.imageio.ImageIO;
public class Intro extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
private Thread thread;
private BufferedImage bg;
private String html =
"<html><body style='color: yellow;'>" +
"<h1>Game</h1>" +
"<p>Welcome to the Game!";
public Intro() {
super();
loadImages();
setLayout(new BorderLayout());
setBorder(new EmptyBorder(40,40,40,40));
add(new JLabel(html), BorderLayout.NORTH);
add(new JTextField("..enter name"), BorderLayout.SOUTH);
}
private void loadImages() {
try {
URL url = new URL("http://pscode.org/media/stromlo2.jpg");
bg = ImageIO.read(url);
setPreferredSize(new Dimension(bg.getWidth(), bg.getHeight()));
} catch (Exception e) {
e.printStackTrace();
}
}
public void addNotify() {
super.addNotify();
thread = new Thread(this);
thread.start();
}
public void run() {
while(true) {
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(bg, 0, 0, this);
}
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, new Intro());
}
}
first load the background image then opaque its property then add the other components on it.
Related
I am trying to rotate a JLabel 90 degrees that shows the current time 90 degrees. After doing some research, most people have recommended using Graphics2D and AffineTransform. This almost works, but when the minute in the time is updated, the new digit appears to merge with the old digit.
This does not happen for the seconds. Does anybody have any idea how to fix this issue or have an alternate solution?
Driver class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Driver extends JFrame implements KeyListener {
private boolean running = true;
ClockWidget clockWidget;
static Dimension screenSize;
public static void main(String[] args) {
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
DisplayMode displayMode = new DisplayMode((int) screenSize.getWidth(), (int) screenSize.getHeight(), 32,
DisplayMode.REFRESH_RATE_UNKNOWN);
new Driver().run(displayMode);
}
public void run(DisplayMode displayMode) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
getContentPane().setBackground(Color.BLACK);
setFont(new Font("Arial", Font.PLAIN, 24));
Screen screen = new Screen();
screen.setFullScreen(displayMode, this);
initClockWidgit();
addKeyListener(this);
System.out.println("RUNNING");
while (running) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
quitProgram(screen);
return;
}
public void initClockWidgit() {
clockWidget = new ClockWidget();
clockWidget.setFont(new Font("Arial", Font.PLAIN, 36));
clockWidget.setForeground(Color.WHITE);
clockWidget.setBackground(Color.BLUE);
clockWidget.setBounds((int) (screenSize.getWidth() * 0.90), (int) (screenSize.getHeight() * 0.10), 250, 100);
add(clockWidget);
new Thread(clockWidget).start();
}
public void quitProgram(Screen screen) {
screen.restoreScreen();
clockWidget.disable();
}
#Override
public void keyPressed(KeyEvent keyEvent) {
int keyCode = keyEvent.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE) {
running = false;
}
keyEvent.consume();
}
#Override
public void keyReleased(KeyEvent keyEvent) {
keyEvent.consume();
}
#Override
public void keyTyped(KeyEvent keyEvent) {
keyEvent.consume();
}
}
ClockWidget Class:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.JLabel;
public class ClockWidget extends RotatedJLabel implements Runnable{
private String currentTime;
private boolean running;
public ClockWidget() {
running = true;
}
#Override
public void run() {
while(running) {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm:ss a");
currentTime = simpleDateFormat.format(calendar.getTime());
setText(currentTime);
}
}
public void disable() {
running = false;
}
}
RotatedJLabel Class:
[import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.Icon;
import javax.swing.JLabel;
public class RotatedJLabel extends JLabel {
public RotatedJLabel() {
super();
}
public RotatedJLabel(Icon image) {
super(image);
}
public RotatedJLabel(Icon image, int horizontalAlignment) {
super(image, horizontalAlignment);
}
public RotatedJLabel(String text) {
super(text);
}
public RotatedJLabel(String text, Icon icon, int horizontalAlignment) {
super(text, icon, horizontalAlignment);
}
public RotatedJLabel(String text, int horizontalAlignment) {
super(text, horizontalAlignment);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform aT = g2.getTransform();
Shape oldshape = g2.getClip();
double x = getWidth()/2.0;
double y = getHeight()/2.0;
aT.rotate(Math.toRadians(90), x, y);
g2.setTransform(aT);
g2.setClip(oldshape);
super.paintComponent(g);
}
}
A few things jump out at me:
I wouldn't use a JLabel for this purpose, it's a complicate component, starting with a JPanel and simply painting the text would be simpler. In my testing it was very hard to get the sizing hints to work correctly when the graphics context was rotated.
You're not managing the component's "new" sizing hints, this could be an issue when coupled with more complex layouts, as the width of the component should now be the height and visa-versa
I'd recommend the key bindings API over KeyListener
Swing is NOT thread safe, updating the UI from outside the context of the UI could produce any number of issues; instead of using a Thread, you should be using a Swing Timer, and since you probably really only want to update the seconds, running it at a much slower speed. See Concurrency in Swing and How to Use Swing Timers for more details
And Calendar and Date are effectively deprecated. See Standard Calendar for more details
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private RotatedLabel timeLabel;
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a");
public TestPane() {
setLayout(new GridBagLayout());
timeLabel = new RotatedLabel(currentTime());
add(timeLabel);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timeLabel.setText(currentTime());
}
});
timer.start();
}
public String currentTime() {
LocalTime lt = LocalTime.now();
return lt.format(formatter);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class RotatedLabel extends JPanel {
private String text;
public RotatedLabel() {
super();
setOpaque(false);
setFont(UIManager.getDefaults().getFont("label.font"));
}
public RotatedLabel(String text) {
this();
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
revalidate();
repaint();
}
protected Dimension getTextBounds() {
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(text), fm.getHeight());
}
#Override
public Dimension getPreferredSize() {
Dimension size = getTextBounds();
return new Dimension(size.height, size.width);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform aT = g2.getTransform();
double x = getWidth() / 2.0;
double y = getHeight() / 2.0;
aT.rotate(Math.toRadians(90), x, y);
g2.setTransform(aT);
FontMetrics fm = g2.getFontMetrics();
float xPos = (getWidth() - fm.stringWidth(getText())) / 2.0f;
float yPos = ((getHeight() - fm.getHeight()) / 2.0f) + fm.getAscent();
g2.drawString(text, xPos, yPos);
g2.dispose();
}
}
}
Now, if you "absolutely, must, no questions asked" use a component like Label, then I recommend using JLayer instead.
Unfourtantly, I've not had time to update my examples to use JLayer, but they use the predecessor library, JXLayer
Java rotating non-square JPanel component
Is there any way I can rotate this 90 degrees?
I'm new on working with Java and Netbeans. In many others languages, it's a simple stuff to do. But after broke my brain thinking, I couldn't. My doubt is simple to explain.
How can I show bitmaps (stored on Hard Drive) in runtime, in a commom JFrame, using java2D? What I need to edit, and or create? Is it simple to do?
Thanks in advance...
The basic process is use Graphics#drawImage to render an image you have previously loaded.
There are a number of things you need in order to achieve this...
An image to paint
A surface to paint on
Luckily, both these are relatively easy to achieve in Swing
See ImageIO for reading images, Reading/Loading an Image
See Performing Custom Painting for more details about how to perform painting in Swing...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ShowMyImage {
public static void main(String[] args) {
new ShowMyImage();
}
public ShowMyImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
ImagePane pane = new ImagePane();
try {
pane.setImg(ImageIO.read(new File("C:\\hold\\thumbnails\\_MTCGAC__Pulling_Cords_by_Dispozition.png")));
} catch (IOException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane() {
}
public void setImg(BufferedImage value) {
if (img != value) {
img = value;
repaint();
}
}
public BufferedImage getImg() {
return img;
}
#Override
public Dimension getPreferredSize() {
BufferedImage img = getImg();
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage img = getImg();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight()- img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
g2d.dispose();
}
}
}
You need, as was told below to extend JPanel class and override paintComponent method in it.
public class DrawImageClass extends JPanel {
private static final long serialVersionUID = 1L;
private Image image;
public DrawImageClass(Image image) throws HeadlessException {
super();
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(image, null, null);
}
}
And then create JFrame and add this class to it.
public class App {
private static final int WIDTH=480, HEIGHT = 640;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(new Dimension(HEIGHT, WIDTH));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
DrawImageClass panel = new DrawImageClass(ImageIO.read(new File(App.class.getResource("/1.png").getPath())));
panel.setPreferredSize(new Dimension(HEIGHT, WIDTH));
frame.add(panel);
frame.setVisible(true);
} catch (Exception e) {
System.out.println("wrong path or smth other");
}
}
}
Example for picture which is in resource folder in project
You can do this with the basic AWT package in java. You will need to extend the JFrame class and override its paintComponent method to display an image there. i.e.
public class MyFrame extends JFrame {
private java.awt.Image bitmap = ImageIO.read(new File("myBitmap.bmp"));
#Override
public void paintComponent(java.awt.Graphics graphics) {
int x = 0;
int y = 0;
int w = bitmap.getWidth(null);
int h = bitmap.getHeight(null);
graphics.drawImage(bitmap, x, y, w, h, this);
}
}
You can simply instantiate it then
MyFrame myFrame = new MyFrame();
myFrame.setPreferredSize(new Dimension(100, 100));
myFrame.setVisible(true);
This is a basic example of course.
I want to take a print screen of what is behind the JFrame, without the JFrame itself. The way I tried was to close the window, wait for a while so it fully closes, then take the print screen and then open it again. The current method is not good for what I need since I need to do it more frequently and waiting for the window to close is too much time. Also, I don't want to close the window for that.
Here is my current code:
public class Offscreen {
private static BufferedImage img;
public static void main(String[] main)
throws AWTException, InterruptedException {
JFrame frame = new JFrame() {
#Override
public void paint(Graphics g) {
if (img != null)
// draw print screen
g.drawImage(img, 0, 0, null);
}
};
frame.setSize(500, 500);
frame.setLocation(700, 0);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setVisible(false);
Thread.sleep(200);
// take the picture
Robot r = new Robot();
img = r.createScreenCapture(frame.getBounds());
// show the source again
frame.setVisible(true);
// print on destiny
frame.repaint();
}
}
"Assuming" you only want to capture the area behind the active frame (and as you say, without the frame), then something like..
import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PrintScreen01 {
public static void main(String[] args) {
new PrintScreen01();
}
private Timer timer;
public PrintScreen01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
final PrintPane printPane = new PrintPane();
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(printPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentMoved(ComponentEvent e) {
timer.restart();
}
#Override
public void componentResized(ComponentEvent e) {
timer.restart();
}
});
timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (frame.isVisible()) {
takeSnapShot(frame, printPane);
}
}
});
timer.setRepeats(false);
frame.setVisible(true);
// takeSnapShot(frame, printPane);
}
});
}
public void takeSnapShot(JFrame frame, PrintPane pane) {
Rectangle bounds = new Rectangle(pane.getLocationOnScreen(), pane.getSize());
frame.setVisible(false);
new SnapShotWorker(frame, pane, bounds).execute();
}
public class SnapShotWorker extends SwingWorker<BufferedImage, BufferedImage> {
private JFrame frame;
private PrintPane pane;
private Rectangle captureBounds;
public SnapShotWorker(JFrame frame, PrintPane pane, Rectangle bounds) {
this.frame = frame;
this.pane = pane;
captureBounds = bounds;
}
#Override
protected BufferedImage doInBackground() throws Exception {
Thread.sleep(125);
BufferedImage snapShot = null;
try {
Robot bot = new Robot();
snapShot = bot.createScreenCapture(captureBounds);
} catch (AWTException ex) {
ex.printStackTrace();
}
Thread.sleep(125);
return snapShot;
}
#Override
protected void done() {
try {
BufferedImage snapShot = get();
pane.setSnapShot(snapShot);
frame.setVisible(true);
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
}
public class PrintPane extends JPanel {
private BufferedImage background;
public PrintPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void setSnapShot(BufferedImage img) {
background = img;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.drawImage(background, 0, 0, this);
g2d.dispose();
}
}
}
}
May help...
Now, I had some issues with the timing of Robot, it would seem that part of the operation is threaded in some way, meaning that unless you got the timing of the frame changing between invisible and visible "just" right, you would actually recapture the frame...annoying...
To try and fix this, and reduce the amount of times I tried capturing the screen, I employed a javax.swing.Timer (to reduce the capture attempts) and a SwingWorker to control the actual snapshot process, taking it out of the Event Dispatching Thread, there by ensuring (to some degree) that the window will be invisible.
I also added some additional lag to ensure that the frame was off the screen long enough to prevent it been capture by the snapshot...
I am making a game by java and it refreshes itself 60 times per second. Every time it executes a loop and I use g2d to draw images and strings. Things work fine if I do g2d.setFont(new Font("Arial", Font.PLAIN, 8)); and drawstring and it would be normal, but if I set the font to some "unfamiliar" fonts and do the same thing, the swing would show white screen in the first second of start up then paint everything correctly and it's apparently too slow (2 secs).
I put a jpanel in a jframe and override the paint() method of jpanel to draw everything I need. I've already used SwingUtilities.invokeLater in my code.
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
public Window(){
add(new Board());
setSize(800,600);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
private class Board extends JPanel {
Font font = new Font("Bitmap", Font.PLAIN, 64);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setFont(font);
g2d.drawString("This is slow", 220,200);
Toolkit.getDefaultToolkit().sync();
g2d.dispose();
g.dispose();
}
}
}
This is not in a loop but it's very laggy.
http://fontsov.com/download-fonts/bitmap1159.html
This is the cutie font that slows our application down. "Arial" will load blazingly fast. How can I make this less laggy?
First and foremost, for best help, create and post your minimal code example program for us to review, test, and possibly fix. Without this, it will be hard for us to fully understand your problem.
Consider:
Overriding paintComponent not paint to get the advantage of double buffering.
Avoid using invokeLater unless you're sure that the code is being called off of the Swing event thread and you are making calls that need to be on the event thread.
Put slow running code in a background thread such as that which can be found using a SwingWorker.
Putting your text in a JLabel, not drawn on a component.
Draw all static images to a BufferedImage, and displaying that in paintComponent. Then draw all changing images, such as your moving sprites, directly in the paintComponent method.
Don't forget to call your super.paintCompmonent(g) within your paintComponent(Graphics g) method override.
Edit
A BufferedImage solution could look like,....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); //do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
paintGame(g2d);
// Toolkit.getDefaultToolkit().sync();
// g2d.dispose();
// g.dispose();
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
mainImage = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
}
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Edit 2
Or with a SwingWorker background thread....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); // do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
paintGame(g2d);
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
imgWorker.addPropertyChangeListener(new ImgWorkerListener());
imgWorker.execute();
}
private class ImgWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
mainImage = imgWorker.get();
// repaint() here if you don't have a game loop running
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
SwingWorker<BufferedImage, Void> imgWorker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
return img;
}
};
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
it's a bit uneconomic to create a new Font each time paint() is called (which happens a lot), you could move that to your constructor.
and the font should be changed to some orthodox fonts (Arial,Calibri etc)
My gif animation flickers too much. I've heard about double buffering that can help but how do I do that to my gif animation? Or is there a better faster shortcut to it. This is just a small test applet thing Im doing for fun but will implement the lessons in class.
Context:
import java.net.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class HiroshimaBlock extends Applet implements ActionListener {
TextField distanceText = new TextField(10);
TextField accelerationText = new TextField(10);
Button security = new Button("Account Manager");
Button launch = new Button("LAUNCH!");
Button Reportl = new Button("Report Logs");
Image dancer;
URL base;
MediaTracker mt;
Timer tm = new Timer(10, this);
TextArea answers = new TextArea("I am ready for your first trip.", 4, 20,
TextArea.SCROLLBARS_NONE);
Image image;
#Override
public void init() {
setSize(550, 500);
// Some messages for the top of the Applet:
addHorizontalLine(Color.orange);
addNewLine();
// JOptionPane.showMessageDialog(null, "HiroshimaBlock",
// "Welcome to HiroshimaBlock", JOptionPane.PLAIN_MESSAGE);
// The two text fields and the launch button:
Frame c = (Frame) this.getParent().getParent();
c.setTitle("HiroshimaBlock");
mt = new MediaTracker(this);
try {
base = getDocumentBase();
} catch (Exception e) {
}
dancer = getImage(base, "dancer1.gif");
mt.addImage(dancer, 9);
try {
mt.waitForAll();
} catch (InterruptedException e) {
}
loadImage();
// add(distanceText);
// add(new Label("Distance of trip in light years"));
addNewLine();
addNewLine();
// add(accelerationText);
// add(new Label("Acceleration of rocket in g's"));
addNewLine();
add(launch);
addNewLine();
add(security);
addNewLine();
add(Reportl);
// A text area for printing the answers:
// answers.setEditable(false);
// add(answers);
addNewLine();
addNewLine();
addHorizontalLine(Color.orange);
}
public void loadImage() {
URL url = getClass().getResource("hsblock.png");
image = getToolkit().getImage(url);
}
public void paint(Graphics g) {
g.drawImage(image, 20, 20, this);
this.security.setLocation(25, 200);
addNewLine();
this.launch.setLocation(25, 230);
this.Reportl.setLocation(25, 260);
this.security.setSize(100, 25);
this.launch.setSize(100, 25);
this.Reportl.setSize(100, 25);
g.drawImage(dancer, 150, 200, this);
tm.start();
}
private void addHorizontalLine(Color c) {
// Add a Canvas 10000 pixels wide but only 1 pixel high, which acts as
// a horizontal line to separate one group of components from the next.
Canvas line = new Canvas();
line.setSize(10000, 1);
line.setBackground(c);
add(line);
}
private void addNewLine() {
// Add a horizontal line in the background color. The line itself is
// invisible, but it serves to force the next Component onto a new line.
addHorizontalLine(getBackground());
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
You want to:
Create a drawing class that extends JPanel (or JComponent)
Override the paintComponent(Graphics g) method of your class.
Call the super's method first in this method
And then do your animation drawing in this method.
This will give you Swing's automatic double buffering which should help smooth out your animation.
Display your drawing JPanel in your JApplet by adding it to the applet's contentPane.
For example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.nio.Buffer;
import javax.swing.*;
public class SimpleAnimation extends JApplet {
#Override
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
DrawPanel drawPanel = new DrawPanel();
getContentPane().add(drawPanel);
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
}
class DrawPanel extends JPanel {
private static final int I_WIDTH = 20;
private static final int I_HEIGHT = 20;
private static final int TIMER_DELAY = 15;
private int x = 0;
private int y = 0;
private BufferedImage img = new BufferedImage(I_WIDTH, I_HEIGHT, BufferedImage.TYPE_INT_ARGB);
public DrawPanel() {
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.red);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillOval(1, 1, I_WIDTH - 2, I_HEIGHT - 2);
g2.dispose();
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, x, y, this);
}
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
repaint();
}
}
}
Well LOL I made it stop flickering by using update LOLOLOL
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends Applet {
Image img;
public void init() {
setSize(700, 700);
img = getImage(getDocumentBase(), "dancer1.gif");
}
public void update(Graphics g) {
g.drawImage(img, 140, 200, this);
}
public void paint(Graphics g) {
update(g);
}
}